mirror of
https://github.com/postmannen/ctrl.git
synced 2025-01-07 20:59:16 +00:00
removed debug printing
fixed typo in readme added useDetectedShell to message, so it can be decided on the message level to use it or not for cliCommand's added so if shell are defined via flag that will be used, and not the default shell of the OS. For the Linux and Darwin operating system we allow to automatically detect shell interpreter, so the user don't have to type "bash", "-c" as the first two arguments of the methodArgs. replaced tail package, and added nil check when reading lines renaming of key related functions, updated doc updated key comments, and added doc section for central node updated doc and error messages
This commit is contained in:
parent
0451a90332
commit
de74c2531e
21 changed files with 199 additions and 84 deletions
4
TODO.md
4
TODO.md
|
@ -1,3 +1,7 @@
|
|||
# TODO
|
||||
|
||||
## Key and ACL updates to use jetstream
|
||||
|
||||
## tailfile
|
||||
|
||||
Replace the hpcloud/tail with <https://github.com/tenebris-tech/tail>
|
||||
|
|
|
@ -127,25 +127,25 @@ func (c *centralAuth) addPublicKey(proc process, msg Message) {
|
|||
c.pki.nodesAcked.mu.Unlock()
|
||||
|
||||
if ok && bytes.Equal(existingKey, msg.Data) {
|
||||
er := fmt.Errorf("info: public key value for REGISTERED node %v is the same, doing nothing", msg.FromNode)
|
||||
er := fmt.Errorf("info: public key value for registered node %v is the same, doing nothing", msg.FromNode)
|
||||
proc.errorKernel.logDebug(er)
|
||||
return
|
||||
}
|
||||
|
||||
c.pki.nodeNotAckedPublicKeys.mu.Lock()
|
||||
existingNotAckedKey, ok := c.pki.nodeNotAckedPublicKeys.KeyMap[msg.FromNode]
|
||||
// We only want to send one notification to the error kernel about new key detection,
|
||||
// so we check if the values are the same as the one we already got before we continue
|
||||
// with registering and logging for the the new key.
|
||||
if ok && bytes.Equal(existingNotAckedKey, msg.Data) {
|
||||
c.pki.nodeNotAckedPublicKeys.mu.Unlock()
|
||||
return
|
||||
}
|
||||
// existingNotAckedKey, ok := c.pki.nodeNotAckedPublicKeys.KeyMap[msg.FromNode]
|
||||
// // We only want to send one notification to the error kernel about new key detection,
|
||||
// // so we check if the values are the same as the one we already got before we continue
|
||||
// // with registering and logging for the the new key.
|
||||
// if ok && bytes.Equal(existingNotAckedKey, msg.Data) {
|
||||
// c.pki.nodeNotAckedPublicKeys.mu.Unlock()
|
||||
// return
|
||||
// }
|
||||
|
||||
c.pki.nodeNotAckedPublicKeys.KeyMap[msg.FromNode] = msg.Data
|
||||
c.pki.nodeNotAckedPublicKeys.mu.Unlock()
|
||||
|
||||
er := fmt.Errorf("info: detected new public key for node: %v. This key will need to be authorized by operator to be allowed into the system", msg.FromNode)
|
||||
er := fmt.Errorf("info: new public key for node: %v. Key needs to be authorized by operator to be allowed into the system by using the keysAllow method", msg.FromNode)
|
||||
c.pki.errorKernel.infoSend(proc, msg, er)
|
||||
c.pki.errorKernel.logDebug(er)
|
||||
}
|
||||
|
@ -294,7 +294,7 @@ func (c *centralAuth) updateHash(proc process, message Message) {
|
|||
|
||||
b, err := cbor.Marshal(sortedNodesAndKeys)
|
||||
if err != nil {
|
||||
er := fmt.Errorf("error: methodKeysAllow, failed to marshal slice, and will not update hash for public keys: %v", err)
|
||||
er := fmt.Errorf("error: updateHash, failed to marshal slice, and will not update hash for public keys: %v", err)
|
||||
c.pki.errorKernel.errSend(proc, message, er, logError)
|
||||
|
||||
return
|
||||
|
|
|
@ -2,9 +2,12 @@ package ctrl
|
|||
|
||||
import (
|
||||
"flag"
|
||||
"fmt"
|
||||
"log"
|
||||
"os"
|
||||
"os/exec"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/joho/godotenv"
|
||||
)
|
||||
|
@ -16,6 +19,8 @@ import (
|
|||
// an if check should be added to the checkConfigValues function
|
||||
// to set default values when reading from config file.
|
||||
type Configuration struct {
|
||||
// Shell on the operating system to use when executing cliCommands
|
||||
ShellOnNode string
|
||||
// ConfigFolder, the location for the configuration folder on disk
|
||||
ConfigFolder string `comment:"ConfigFolder, the location for the configuration folder on disk"`
|
||||
// The folder where the socket file should live
|
||||
|
@ -152,6 +157,7 @@ func NewConfiguration() *Configuration {
|
|||
}
|
||||
|
||||
//flag.StringVar(&c.ConfigFolder, "configFolder", fc.ConfigFolder, "Defaults to ./usr/local/ctrl/etc/. *NB* This flag is not used, if your config file are located somwhere else than default set the location in an env variable named CONFIGFOLDER")
|
||||
flag.StringVar(&c.ShellOnNode, "shellOnNode", CheckEnv("SHELL_ON_NODE", c.ShellOnNode).(string), "set a value to override the default shell used as interpreter for running cliCommand's on node.")
|
||||
flag.StringVar(&c.SocketFolder, "socketFolder", CheckEnv("SOCKET_FOLDER", c.SocketFolder).(string), "folder who contains the socket file. Defaults to ./tmp/. If other folder is used this flag must be specified at startup.")
|
||||
flag.StringVar(&c.ReadFolder, "readFolder", CheckEnv("READ_FOLDER", c.ReadFolder).(string), "folder who contains the readfolder. Defaults to ./readfolder/. If other folder is used this flag must be specified at startup.")
|
||||
flag.StringVar(&c.TCPListener, "tcpListener", CheckEnv("TCP_LISTENER", c.TCPListener).(string), "start up a TCP listener in addition to the Unix Socket, to give messages to the system. e.g. localhost:8888. No value means not to start the listener, which is default. NB: You probably don't want to start this on any other interface than localhost")
|
||||
|
@ -220,14 +226,32 @@ func NewConfiguration() *Configuration {
|
|||
log.Fatalf("error: the centralNodeName config option or flag cannot be empty, check -help\n")
|
||||
}
|
||||
|
||||
if c.ShellOnNode == "" {
|
||||
c.ShellOnNode = getShell()
|
||||
}
|
||||
fmt.Printf("\n******** DETECTED SHELL: %v\n\n", c.ShellOnNode)
|
||||
|
||||
flag.Parse()
|
||||
|
||||
return &c
|
||||
}
|
||||
|
||||
func getShell() string {
|
||||
out, err := exec.Command("echo", os.ExpandEnv("$SHELL")).Output()
|
||||
if err != nil {
|
||||
log.Fatalf("error: unable to detect shell: %v\n", err)
|
||||
}
|
||||
|
||||
shell := string(out)
|
||||
shell = strings.TrimSuffix(shell, "\n")
|
||||
|
||||
return string(shell)
|
||||
}
|
||||
|
||||
// Get a Configuration struct with the default values set.
|
||||
func newConfigurationDefaults() Configuration {
|
||||
c := Configuration{
|
||||
ShellOnNode: "",
|
||||
ConfigFolder: "./etc/",
|
||||
SocketFolder: "./tmp",
|
||||
ReadFolder: "./readfolder",
|
||||
|
|
|
@ -12,14 +12,19 @@
|
|||
# Core ctrl
|
||||
|
||||
- [Messaging](./core_messaging_overview.md)
|
||||
- [Message fields](./core_messaging_message_fields.md)
|
||||
- [Message jetstream/broadcast](./core_messaging_jetstream.md)
|
||||
- [Request Methods](./core_request_methods.md)
|
||||
- [Message fields](./core_messaging_message_fields.md)
|
||||
- [Message jetstream/broadcast](./core_messaging_jetstream.md)
|
||||
- [Request Methods](./core_request_methods.md)
|
||||
- [{{CTRL_DATA}} variable](./core_messaging_CTRL_DATA.md)
|
||||
- [{{CTRL_FILE}} variable](./core_messaging_CTRL_FILE.md)
|
||||
- [Nats timeouts](./core_nats_timeouts.md)
|
||||
- [Startup folder](./core_startup_folder.md)
|
||||
- [{{CTRL_DATA}} variable](./core_messaging_CTRL_DATA.md)
|
||||
- [{{CTRL_FILE}} variable](./core_messaging_CTRL_FILE.md)
|
||||
- [Errors](./core_errors.md)
|
||||
- [central](./core_central.md)
|
||||
- [hello messages](./core_hello_messages.md)
|
||||
- [signing keys](./core_signing_keys.md)
|
||||
- [ACL](./core_acl.md)
|
||||
- [audit log](./core_audit_log.md)
|
||||
|
||||
# Examples standard messages
|
||||
|
||||
|
@ -32,4 +37,4 @@
|
|||
|
||||
# Using ctrl
|
||||
|
||||
- [ctrl as github action runner](usecase-ctrl-as-github-action-runner)
|
||||
- [ctrl as github action runner](usecase-ctrl-as-github-action-runner)
|
||||
|
|
1
doc/src/core_acl.md
Normal file
1
doc/src/core_acl.md
Normal file
|
@ -0,0 +1 @@
|
|||
# ACL
|
1
doc/src/core_audit_log.md
Normal file
1
doc/src/core_audit_log.md
Normal file
|
@ -0,0 +1 @@
|
|||
# audit log
|
3
doc/src/core_central.md
Normal file
3
doc/src/core_central.md
Normal file
|
@ -0,0 +1,3 @@
|
|||
# central
|
||||
|
||||
To get functionality like central audit log, signing keys, authorization with ACL's and hello messages one node should be started with the node name **central**
|
11
doc/src/core_hello_messages.md
Normal file
11
doc/src/core_hello_messages.md
Normal file
|
@ -0,0 +1,11 @@
|
|||
# Hello messages
|
||||
|
||||
All nodes can send hello messages to inform that they are up. The interval between sending a hello message can be set with the `START_PUB_HELLO` environment variable.
|
||||
|
||||
Hello messages are sent to the node with the name **central**. When a hello message are received on central, information with the time and node name will be stored in the **ctrl data folder**
|
||||
|
||||
## Public keys
|
||||
|
||||
ctrl nodes can use ed25519 keys for signing messages, so each ctrl instance will generate a public and private key pair on startup. The public keys are sent to the central server with the hello messages.
|
||||
|
||||
To read more about signing keys here: [signing keys](./core_signing_keys.md)
|
1
doc/src/core_signing_keys.md
Normal file
1
doc/src/core_signing_keys.md
Normal file
|
@ -0,0 +1 @@
|
|||
# signing keys
|
|
@ -8,9 +8,48 @@ Messages put in the startup folder will not be sent to the broker but handled lo
|
|||
|
||||
This can be really handy when you have some 1-off job you want to done at startup, like some cleaning up.
|
||||
|
||||
Another example could be that you have some local prometheus metrics you want to scrape every 5 minutes, and you want to send them to some central metrics system.
|
||||
## Example reqest metrics from nodes
|
||||
|
||||
#### How to send the reply to another node
|
||||
Another example could be that you have some local prometheus metrics you want to scrape every 5 minutes, and you want to send them to some central metrics system.
|
||||
|
||||
```yaml
|
||||
---
|
||||
- toNodes:
|
||||
- ["node1","node2"]
|
||||
method: httpGet
|
||||
methodArgs:
|
||||
- "http://localhost:8080/metrics"
|
||||
replyMethod: file
|
||||
methodTimeout: 5
|
||||
directory: metrics
|
||||
fileName: metrics.html
|
||||
schedule : [120,999999999]
|
||||
```
|
||||
|
||||
The example above will send out a request to node1 and node2 every 120 second to scrape the metrics and write the results that came back to a folder named **data/metrics** in the current running directory.
|
||||
|
||||
## Example read metrics locally first, and then send to remote node
|
||||
|
||||
But we can also make the nodes publish their metrics instead of requesting it by putting a message in each nodes startup folder, set the **toNode** field to local, and instead use the **fromNode** field to decide where to deliver the result.
|
||||
|
||||
```yaml
|
||||
---
|
||||
- toNodes:
|
||||
- ["local"]
|
||||
fromNode: my-metrics-node
|
||||
method: httpGet
|
||||
methodArgs:
|
||||
- "http://localhost:8080/metrics"
|
||||
replyMethod: file
|
||||
methodTimeout: 5
|
||||
directory: metrics
|
||||
fileName: metrics.html
|
||||
schedule : [120,999999999]
|
||||
```
|
||||
|
||||
In the above example, the httpGet will be run on the local node, and the result will be sent to my-metrics-node.
|
||||
|
||||
### How to send the reply to another node further explained
|
||||
|
||||
Normally the **fromNode** field is automatically filled in with the node name of the node where a message originated. Since messages within the startup folder is not received from another node via the normal message path we need set the **fromNode** field in the message to where we want the reply (result) delivered.
|
||||
|
||||
|
@ -38,4 +77,4 @@ Since messages used in startup folder are ment to be delivered locally we can si
|
|||
|
||||
```
|
||||
|
||||
This example message will be read at startup, and executed on the local node where it was read, the method will be executed, and the result of the method will be sent to **central**.
|
||||
This example message will be read at startup, and executed on the local node where it was read, the method will be executed, and the result of the method will be sent to **central**. This is basically the same as the previous example, but we're using cliCommand method with curl instead of the httpGet method.
|
||||
|
|
|
@ -1,6 +1,28 @@
|
|||
# cliCommand
|
||||
|
||||
In JSON.
|
||||
With **cliCommand** you specify the command to run in **methodArgs** prefixed with the interpreter to use, for example with bash **bash** `"bash","-c","tree"`.
|
||||
|
||||
On Linux and Darwin, the shell interpreter can also be auto detected by setting the value of **useDetectedShell** in the message to **true**. If set to true the methodArgs only need a single string value with command to run. Example below.
|
||||
|
||||
```yaml
|
||||
---
|
||||
- toNodes:
|
||||
- node2
|
||||
useDetectedShell: true
|
||||
method: cliCommand
|
||||
methodArgs:
|
||||
- |
|
||||
rm -rf ./data & systemctl restart ctrl
|
||||
|
||||
replyMethod: fileAppend
|
||||
ACKTimeout: 30
|
||||
retries: 1
|
||||
ACKTimeout: 30
|
||||
directory: system
|
||||
fileName: system.log
|
||||
```
|
||||
|
||||
## Example in JSON
|
||||
|
||||
```json
|
||||
[
|
||||
|
@ -18,6 +40,8 @@ In JSON.
|
|||
]
|
||||
```
|
||||
|
||||
## Example in YAML
|
||||
|
||||
In YAML.
|
||||
|
||||
```yaml
|
||||
|
|
3
go.mod
3
go.mod
|
@ -7,7 +7,6 @@ require (
|
|||
github.com/fxamacker/cbor/v2 v2.5.0
|
||||
github.com/go-playground/validator/v10 v10.10.1
|
||||
github.com/google/uuid v1.3.0
|
||||
github.com/hpcloud/tail v1.0.0
|
||||
github.com/jinzhu/copier v0.4.0
|
||||
github.com/joho/godotenv v1.5.1
|
||||
github.com/klauspost/compress v1.17.2
|
||||
|
@ -16,6 +15,7 @@ require (
|
|||
github.com/nats-io/nkeys v0.4.7
|
||||
github.com/pkg/profile v1.7.0
|
||||
github.com/prometheus/client_golang v1.14.0
|
||||
github.com/tenebris-tech/tail v1.0.5
|
||||
go.etcd.io/bbolt v1.3.7
|
||||
golang.org/x/crypto v0.18.0
|
||||
golang.org/x/exp v0.0.0-20230321023759-10a507213a29
|
||||
|
@ -43,6 +43,5 @@ require (
|
|||
golang.org/x/text v0.14.0 // indirect
|
||||
golang.org/x/time v0.0.0-20220609170525-579cf78fd858 // indirect
|
||||
google.golang.org/protobuf v1.30.0 // indirect
|
||||
gopkg.in/fsnotify.v1 v1.4.7 // indirect
|
||||
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 // indirect
|
||||
)
|
||||
|
|
26
go.sum
26
go.sum
|
@ -11,8 +11,6 @@ github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c
|
|||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/felixge/fgprof v0.9.3 h1:VvyZxILNuCiUCSXtPtYmmtGvb65nqXh2QFWc0Wpf2/g=
|
||||
github.com/felixge/fgprof v0.9.3/go.mod h1:RdbpDgzqYVh/T9fPELJyV7EYJuHB55UTEULNun8eiPw=
|
||||
github.com/fsnotify/fsnotify v1.6.0 h1:n+5WquG0fcWoWp6xPWfHdbskMCQaFnG6PfBrh1Ky4HY=
|
||||
github.com/fsnotify/fsnotify v1.6.0/go.mod h1:sl3t1tCWJFWoRz9R8WJCbQihKKwmorjAbSClcnxKAGw=
|
||||
github.com/fsnotify/fsnotify v1.8.0 h1:dAwr6QBTBZIkG8roQaJjGof0pp0EeF+tNV7YBP3F/8M=
|
||||
github.com/fsnotify/fsnotify v1.8.0/go.mod h1:8jBTzvmWwFyi3Pb8djgCCO5IBqzKJ/Jwo8TRcHyHii0=
|
||||
github.com/fxamacker/cbor/v2 v2.5.0 h1:oHsG0V/Q6E/wqTS2O1Cozzsy69nqCiguo5Q1a1ADivE=
|
||||
|
@ -38,15 +36,11 @@ github.com/google/pprof v0.0.0-20230323073829-e72429f035bd h1:r8yyd+DJDmsUhGrRBx
|
|||
github.com/google/pprof v0.0.0-20230323073829-e72429f035bd/go.mod h1:79YE0hCXdHag9sBkw2o+N/YnZtTkXi0UT9Nnixa5eYk=
|
||||
github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I=
|
||||
github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
github.com/hpcloud/tail v1.0.0 h1:nfCOvKYfkgYP8hkirhJocXT2+zOD8yUNjXaWfTlyFKI=
|
||||
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
|
||||
github.com/ianlancetaylor/demangle v0.0.0-20210905161508-09a460cdf81d/go.mod h1:aYm2/VgdVmcIU8iMfdMvDMsRAQjcfZSKFby6HOFvi/w=
|
||||
github.com/jinzhu/copier v0.4.0 h1:w3ciUoD19shMCRargcpm0cm91ytaBhDvuRpz1ODO/U8=
|
||||
github.com/jinzhu/copier v0.4.0/go.mod h1:DfbEm0FYsaqBcKcFuvmOZb218JkPGtvSHsKg8S8hyyg=
|
||||
github.com/joho/godotenv v1.5.1 h1:7eLL/+HRGLY0ldzfGMeQkb7vMd0as4CfYvUVzLqw0N0=
|
||||
github.com/joho/godotenv v1.5.1/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4=
|
||||
github.com/klauspost/compress v1.17.0 h1:Rnbp4K9EjcDuVuHtd0dgA4qNuv9yKDYKK1ulpJwgrqM=
|
||||
github.com/klauspost/compress v1.17.0/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE=
|
||||
github.com/klauspost/compress v1.17.2 h1:RlWWUY/Dr4fL8qk9YG7DTZ7PDgME2V4csBXA8L/ixi4=
|
||||
github.com/klauspost/compress v1.17.2/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE=
|
||||
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
|
||||
|
@ -67,13 +61,9 @@ github.com/nats-io/jwt/v2 v2.2.1-0.20220330180145-442af02fd36a h1:lem6QCvxR0Y28g
|
|||
github.com/nats-io/jwt/v2 v2.2.1-0.20220330180145-442af02fd36a/go.mod h1:0tqz9Hlu6bCBFLWAASKhE5vUA4c24L9KPUUgvwumE/k=
|
||||
github.com/nats-io/nats-server/v2 v2.8.4 h1:0jQzze1T9mECg8YZEl8+WYUXb9JKluJfCBriPUtluB4=
|
||||
github.com/nats-io/nats-server/v2 v2.8.4/go.mod h1:8zZa+Al3WsESfmgSs98Fi06dRWLH5Bnq90m5bKD/eT4=
|
||||
github.com/nats-io/nats.go v1.25.0 h1:t5/wCPGciR7X3Mu8QOi4jiJaXaWM8qtkLu4lzGZvYHE=
|
||||
github.com/nats-io/nats.go v1.25.0/go.mod h1:D2WALIhz7V8M0pH8Scx8JZXlg6Oqz5VG+nQkK8nJdvg=
|
||||
github.com/nats-io/nats.go v1.37.0 h1:07rauXbVnnJvv1gfIyghFEo6lUcYRY0WXc3x7x0vUxE=
|
||||
github.com/nats-io/nats.go v1.37.0/go.mod h1:Ubdu4Nh9exXdSz0RVWRFBbRfrbSxOYd26oF0wkWclB8=
|
||||
github.com/nats-io/nkeys v0.3.0/go.mod h1:gvUNGjVcM2IPr5rCsRsC6Wb3Hr2CQAm08dsxtV6A5y4=
|
||||
github.com/nats-io/nkeys v0.4.4 h1:xvBJ8d69TznjcQl9t6//Q5xXuVhyYiSos6RPtvQNTwA=
|
||||
github.com/nats-io/nkeys v0.4.4/go.mod h1:XUkxdLPTufzlihbamfzQ7mw/VGx6ObUs+0bN5sNvt64=
|
||||
github.com/nats-io/nkeys v0.4.7 h1:RwNJbbIdYCoClSDNY7QVKZlyb/wfT6ugvFCiKy6vDvI=
|
||||
github.com/nats-io/nkeys v0.4.7/go.mod h1:kqXRgRDPlGy7nGaEDMuYzmiJCIAAWDK0IMBtDmGD0nc=
|
||||
github.com/nats-io/nuid v1.0.1 h1:5iA8DT8V7q8WK2EScv2padNa/rTESc1KdnPw4TC2paw=
|
||||
|
@ -102,14 +92,14 @@ github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/
|
|||
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
|
||||
github.com/stretchr/testify v1.8.1 h1:w7B6lhMri9wdJUVmEZPGGhZzrYTPvgJArz7wNPgYKsk=
|
||||
github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
|
||||
github.com/tenebris-tech/tail v1.0.5 h1:gKDA1qEP+kxG/SqaFzJWC/5jLHlG1y4hgibSPHdicrY=
|
||||
github.com/tenebris-tech/tail v1.0.5/go.mod h1:RpxaZO+UNwbKgXA6VzHdR5FTLTM0pk9zZU/mmHxUeZQ=
|
||||
github.com/x448/float16 v0.8.4 h1:qLwI1I70+NjRFUR3zs1JPUCgaCXSh3SW62uAKT1mSBM=
|
||||
github.com/x448/float16 v0.8.4/go.mod h1:14CWIYCyZA/cWjXOioeEpHeN/83MdbZDRQHoFcYsOfg=
|
||||
go.etcd.io/bbolt v1.3.7 h1:j+zJOnnEjF/kyHlDDgGnVL/AIqIJPq8UoB2GSNfkUfQ=
|
||||
go.etcd.io/bbolt v1.3.7/go.mod h1:N9Mkw9X8x5fupy0IKsmuqVtoGDyxsaDlbk4Rd05IAQw=
|
||||
golang.org/x/crypto v0.0.0-20210314154223-e6e6c4f2bb5b/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4=
|
||||
golang.org/x/crypto v0.0.0-20211215153901-e495a2d5b3d3/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
|
||||
golang.org/x/crypto v0.7.0 h1:AvwMYaRytfdeVt3u6mLaxYtErKYjxA2OXjJ1HHq6t3A=
|
||||
golang.org/x/crypto v0.7.0/go.mod h1:pYwdfH91IfpZVANVyUOhSIPZaFoJGxTFbZhFTx+dXZU=
|
||||
golang.org/x/crypto v0.18.0 h1:PGVlW0xEltQnzFZ55hkuX5+KLyrMYhHld1YHO4AKcdc=
|
||||
golang.org/x/crypto v0.18.0/go.mod h1:R0j02AL6hcrfOiy9T4ZYp/rcWeMxM3L6QYxlOuEG1mg=
|
||||
golang.org/x/exp v0.0.0-20230321023759-10a507213a29 h1:ooxPy7fPvB4kwsA2h+iBNHkAbp/4JxTSwCmvdjEYmug=
|
||||
|
@ -123,22 +113,14 @@ golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7w
|
|||
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20210806184541-e5e7981a1069/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20211007075335-d3039528d8ac/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220908164124-27713097b956/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.6.0 h1:MVltZSvRTcU2ljQOhs94SXPftV6DCNnZViHeQps87pQ=
|
||||
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.16.0 h1:xWw16ngr6ZMtmxDyKyIgsE93KNKz5HKmMa3b8ALHidU=
|
||||
golang.org/x/sys v0.16.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/sys v0.27.0 h1:wBqf8DvsY9Y/2P8gAfPDEYNuS30J4lPHJxXSb/nJZ+s=
|
||||
golang.org/x/sys v0.27.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||
golang.org/x/term v0.6.0 h1:clScbb1cHjoCkyRbWwBEUZ5H/tIFu5TAXIqaZD0Gcjw=
|
||||
golang.org/x/term v0.6.0/go.mod h1:m6U89DPEgQRMq3DNkDClhWw02AUbt2daBVO4cn4Hv9U=
|
||||
golang.org/x/term v0.16.0 h1:m+B6fahuftsE9qjo0VWp2FW0mB3MTJvR0BaMQrq0pmE=
|
||||
golang.org/x/term v0.16.0/go.mod h1:yn7UURbUtPyrVJPGPq404EukNFxcm/foM+bV/bfcDsY=
|
||||
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
|
||||
golang.org/x/text v0.8.0 h1:57P1ETyNKtuIjB4SRd15iJxuhj8Gc416Y78H3qgMh68=
|
||||
golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
|
||||
golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ=
|
||||
golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
|
||||
golang.org/x/time v0.0.0-20220609170525-579cf78fd858 h1:Dpdu/EMxGMFgq0CeYMh4fazTD2vtlZRYE7wyynxJb9U=
|
||||
|
@ -154,8 +136,6 @@ gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8
|
|||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
|
||||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
|
||||
gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
|
||||
gopkg.in/fsnotify.v1 v1.4.7 h1:xOHLXZwVvI9hhs+cLKq5+I5onOuwQLhQwiu63xxlHs4=
|
||||
gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
|
||||
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ=
|
||||
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
|
||||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
|
|
|
@ -87,6 +87,8 @@ type Message struct {
|
|||
PreviousMessage *Message
|
||||
// Schedule
|
||||
Schedule []int `json:"schedule" yaml:"schedule"`
|
||||
// Use auto detection of shell for cliCommands
|
||||
UseDetectedShell bool `json:"useDetectedShell" yaml:"useDetectedShell"`
|
||||
}
|
||||
|
||||
// --- Subject
|
||||
|
|
|
@ -112,7 +112,7 @@ func (p *processes) Start(proc process) {
|
|||
|
||||
if proc.configuration.StartProcesses.StartSubHello {
|
||||
|
||||
proc.startup.startProcess(proc, Hello, procFuncHello)
|
||||
proc.startup.startProcess(proc, Hello, procFuncHelloSubscriber)
|
||||
}
|
||||
|
||||
if proc.configuration.StartProcesses.IsCentralErrorLogger {
|
||||
|
|
|
@ -198,7 +198,7 @@ func (m Method) GetMethodsAvailable() MethodsAvailable {
|
|||
TailFile: HandlerFunc(methodTailFile),
|
||||
PublicKey: HandlerFunc(methodPublicKey),
|
||||
KeysRequestUpdate: HandlerFunc(methodKeysRequestUpdate),
|
||||
KeysDeliverUpdate: HandlerFunc(methodKeysDeliverUpdate),
|
||||
KeysDeliverUpdate: HandlerFunc(methodKeysReceiveUpdate),
|
||||
KeysAllow: HandlerFunc(methodKeysAllow),
|
||||
KeysDelete: HandlerFunc(methodKeysDelete),
|
||||
|
||||
|
|
|
@ -3,8 +3,10 @@ package ctrl
|
|||
import (
|
||||
"bufio"
|
||||
"bytes"
|
||||
"context"
|
||||
"fmt"
|
||||
"os/exec"
|
||||
"runtime"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
@ -27,8 +29,6 @@ func methodCliCommand(proc process, message Message, node string) ([]byte, error
|
|||
go func() {
|
||||
defer proc.processes.wg.Done()
|
||||
|
||||
var a []string
|
||||
|
||||
switch {
|
||||
case len(message.MethodArgs) < 1:
|
||||
er := fmt.Errorf("error: methodCliCommand: got <1 number methodArgs")
|
||||
|
@ -36,12 +36,8 @@ func methodCliCommand(proc process, message Message, node string) ([]byte, error
|
|||
newReplyMessage(proc, msgForErrors, []byte(er.Error()))
|
||||
|
||||
return
|
||||
case len(message.MethodArgs) >= 0:
|
||||
a = message.MethodArgs[1:]
|
||||
}
|
||||
|
||||
c := message.MethodArgs[0]
|
||||
|
||||
// Get a context with the timeout specified in message.MethodTimeout.
|
||||
ctx, cancel := getContextForMethodTimeout(proc.ctx, message)
|
||||
|
||||
|
@ -70,7 +66,7 @@ func methodCliCommand(proc process, message Message, node string) ([]byte, error
|
|||
}
|
||||
}
|
||||
|
||||
cmd := exec.CommandContext(ctx, c, a...)
|
||||
cmd := getCmdAndArgs(ctx, proc, message)
|
||||
|
||||
// Check for the use of env variable for CTRL_DATA, and set env if found.
|
||||
if foundEnvData {
|
||||
|
@ -87,6 +83,7 @@ func methodCliCommand(proc process, message Message, node string) ([]byte, error
|
|||
err := cmd.Run()
|
||||
if err != nil {
|
||||
er := fmt.Errorf("error: methodCliCommand: cmd.Run failed : %v, methodArgs: %v, error_output: %v", err, message.MethodArgs, stderr.String())
|
||||
|
||||
proc.errorKernel.errSend(proc, message, er, logWarning)
|
||||
newReplyMessage(proc, msgForErrors, []byte(er.Error()))
|
||||
}
|
||||
|
@ -149,8 +146,6 @@ func methodCliCommandCont(proc process, message Message, node string) ([]byte, e
|
|||
// fmt.Printf(" * DONE *\n")
|
||||
}()
|
||||
|
||||
var a []string
|
||||
|
||||
switch {
|
||||
case len(message.MethodArgs) < 1:
|
||||
er := fmt.Errorf("error: methodCliCommand: got <1 number methodArgs")
|
||||
|
@ -158,12 +153,8 @@ func methodCliCommandCont(proc process, message Message, node string) ([]byte, e
|
|||
newReplyMessage(proc, msgForErrors, []byte(er.Error()))
|
||||
|
||||
return
|
||||
case len(message.MethodArgs) >= 0:
|
||||
a = message.MethodArgs[1:]
|
||||
}
|
||||
|
||||
c := message.MethodArgs[0]
|
||||
|
||||
// Get a context with the timeout specified in message.MethodTimeout.
|
||||
ctx, cancel := getContextForMethodTimeout(proc.ctx, message)
|
||||
// deadline, _ := ctx.Deadline()
|
||||
|
@ -176,7 +167,7 @@ func methodCliCommandCont(proc process, message Message, node string) ([]byte, e
|
|||
go func() {
|
||||
defer proc.processes.wg.Done()
|
||||
|
||||
cmd := exec.CommandContext(ctx, c, a...)
|
||||
cmd := getCmdAndArgs(ctx, proc, message)
|
||||
|
||||
// Using cmd.StdoutPipe here so we are continuosly
|
||||
// able to read the out put of the command.
|
||||
|
@ -254,3 +245,42 @@ func methodCliCommandCont(proc process, message Message, node string) ([]byte, e
|
|||
ackMsg := []byte("confirmed from: " + node + ": " + fmt.Sprint(message.ID))
|
||||
return ackMsg, nil
|
||||
}
|
||||
|
||||
// getCmdAndArgs will return a *exec.Cmd.
|
||||
func getCmdAndArgs(ctx context.Context, proc process, message Message) *exec.Cmd {
|
||||
var cmd *exec.Cmd
|
||||
|
||||
// UseDetectedShell defaults to false , or it was not set in message.
|
||||
// Return a cmd based only on what was defined in the message.
|
||||
if !message.UseDetectedShell {
|
||||
cmd = exec.CommandContext(ctx, message.MethodArgs[0], message.MethodArgs[1:]...)
|
||||
return cmd
|
||||
}
|
||||
|
||||
// UseDetectedShell have been set to true in message.
|
||||
//
|
||||
// Check if a shell have been detected on the node.
|
||||
if proc.configuration.ShellOnNode != "" {
|
||||
switch runtime.GOOS {
|
||||
// If we have a supported os, return the *exec.Cmd based on the
|
||||
// detected shell on the node, and the args defined in the message.
|
||||
case "linux", "darwin":
|
||||
args := []string{"-c"}
|
||||
args = append(args, message.MethodArgs...)
|
||||
|
||||
cmd = exec.CommandContext(ctx, proc.configuration.ShellOnNode, args...)
|
||||
return cmd
|
||||
|
||||
// Not supported OS, use cmd and args defined in message only.
|
||||
default:
|
||||
cmd = exec.CommandContext(ctx, message.MethodArgs[0], message.MethodArgs[1:]...)
|
||||
return cmd
|
||||
}
|
||||
}
|
||||
|
||||
//args := []string{"-c"}
|
||||
//args = append(args, message.MethodArgs...)
|
||||
//cmd = exec.CommandContext(ctx, proc.configuration.ShellOnNode, args...)
|
||||
|
||||
return cmd
|
||||
}
|
||||
|
|
|
@ -8,7 +8,7 @@ import (
|
|||
"os"
|
||||
"path/filepath"
|
||||
|
||||
"github.com/hpcloud/tail"
|
||||
"github.com/tenebris-tech/tail"
|
||||
)
|
||||
|
||||
func reqWriteFileOrSocket(isAppend bool, proc process, message Message) error {
|
||||
|
@ -159,6 +159,9 @@ func methodTailFile(proc process, message Message, node string) ([]byte, error)
|
|||
for {
|
||||
select {
|
||||
case line := <-t.Lines:
|
||||
if line == nil {
|
||||
return
|
||||
}
|
||||
outCh <- []byte(line.Text + "\n")
|
||||
case <-ctx.Done():
|
||||
return
|
||||
|
|
|
@ -35,9 +35,6 @@ func methodPublicKey(proc process, message Message, node string) ([]byte, error)
|
|||
// case proc.toRingbufferCh <- []subjectAndMessage{sam}:
|
||||
case <-ctx.Done():
|
||||
case out := <-outCh:
|
||||
|
||||
// Prepare and queue for sending a new message with the output
|
||||
// of the action executed.
|
||||
newReplyMessage(proc, message, out)
|
||||
}
|
||||
}()
|
||||
|
@ -166,7 +163,7 @@ func procFuncKeysRequestUpdate(ctx context.Context, proc process, procFuncCh cha
|
|||
// ----
|
||||
|
||||
// Handler to receive the public keys from a central server.
|
||||
func methodKeysDeliverUpdate(proc process, message Message, node string) ([]byte, error) {
|
||||
func methodKeysReceiveUpdate(proc process, message Message, node string) ([]byte, error) {
|
||||
// Get a context with the timeout specified in message.MethodTimeout.
|
||||
|
||||
ctx, _ := getContextForMethodTimeout(proc.ctx, message)
|
||||
|
@ -198,11 +195,11 @@ func methodKeysDeliverUpdate(proc process, message Message, node string) ([]byte
|
|||
|
||||
err := json.Unmarshal(message.Data, &keysAndHash)
|
||||
if err != nil {
|
||||
er := fmt.Errorf("error: REQKeysDeliverUpdate : json unmarshal failed: %v, message: %v", err, message)
|
||||
er := fmt.Errorf("error: methodKeysReceiveUpdate : json unmarshal failed: %v, message: %v", err, message)
|
||||
proc.errorKernel.errSend(proc, message, er, logWarning)
|
||||
}
|
||||
|
||||
er := fmt.Errorf("<---- REQKeysDeliverUpdate: after unmarshal, nodeAuth keysAndhash contains: %+v", keysAndHash)
|
||||
er := fmt.Errorf("<---- methodKeysReceiveUpdate: after unmarshal, nodeAuth keysAndhash contains: %+v", keysAndHash)
|
||||
proc.errorKernel.logDebug(er)
|
||||
|
||||
// If the received map was empty we also want to delete all the locally stored keys,
|
||||
|
@ -216,7 +213,7 @@ func methodKeysDeliverUpdate(proc process, message Message, node string) ([]byte
|
|||
proc.nodeAuth.publicKeys.mu.Unlock()
|
||||
|
||||
if err != nil {
|
||||
er := fmt.Errorf("error: REQKeysDeliverUpdate : json unmarshal failed: %v, message: %v", err, message)
|
||||
er := fmt.Errorf("error: methodKeysReceiveUpdate : json unmarshal failed: %v, message: %v", err, message)
|
||||
proc.errorKernel.errSend(proc, message, er, logWarning)
|
||||
}
|
||||
|
||||
|
@ -225,18 +222,12 @@ func methodKeysDeliverUpdate(proc process, message Message, node string) ([]byte
|
|||
|
||||
err = proc.nodeAuth.publicKeys.saveToFile()
|
||||
if err != nil {
|
||||
er := fmt.Errorf("error: REQKeysDeliverUpdate : save to file failed: %v, message: %v", err, message)
|
||||
er := fmt.Errorf("error: methodKeysReceiveUpdate : save to file failed: %v, message: %v", err, message)
|
||||
proc.errorKernel.errSend(proc, message, er, logWarning)
|
||||
}
|
||||
|
||||
// Prepare and queue for sending a new message with the output
|
||||
// of the action executed.
|
||||
// newReplyMessage(proc, message, out)
|
||||
}
|
||||
}()
|
||||
|
||||
// Send back an ACK message.
|
||||
// ackMsg := []byte("confirmed from: " + node + ": " + fmt.Sprint(message.ID))
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
|
|
|
@ -61,7 +61,7 @@ func methodOpProcessStart(proc process, message Message, node string) ([]byte, e
|
|||
method := Method(m)
|
||||
tmpH := mt.getHandler(Method(method))
|
||||
if tmpH == nil {
|
||||
er := fmt.Errorf("error: OpProcessStart: no such request type defined: %v" + m)
|
||||
er := fmt.Errorf("error: OpProcessStart: no such request type defined: %v", m)
|
||||
proc.errorKernel.errSend(proc, message, er, logWarning)
|
||||
return
|
||||
}
|
||||
|
@ -119,7 +119,7 @@ func methodOpProcessStop(proc process, message Message, node string) ([]byte, er
|
|||
method := Method(methodString)
|
||||
tmpH := mt.getHandler(Method(method))
|
||||
if tmpH == nil {
|
||||
er := fmt.Errorf("error: OpProcessStop: no such request type defined: %v, check that the methodArgs are correct: " + methodString)
|
||||
er := fmt.Errorf("error: OpProcessStop: no such request type defined: %v, check that the methodArgs are correct: ", methodString)
|
||||
proc.errorKernel.errSend(proc, message, er, logWarning)
|
||||
return
|
||||
}
|
||||
|
|
|
@ -49,10 +49,7 @@ func methodHello(proc process, message Message, node string) ([]byte, error) {
|
|||
proc.errorKernel.errSend(proc, message, er, logWarning)
|
||||
}
|
||||
|
||||
// --------------------------
|
||||
|
||||
// send the message to the procFuncCh which is running alongside the process
|
||||
// and can hold registries and handle special things for an individual process.
|
||||
// The handling of the public key that is in the message.Data field is handled in the procfunc.
|
||||
proc.procFuncCh <- message
|
||||
|
||||
ackMsg := []byte("confirmed from: " + node + ": " + fmt.Sprint(message.ID))
|
||||
|
@ -66,7 +63,7 @@ func methodHello(proc process, message Message, node string) ([]byte, error) {
|
|||
// received, the handler will deliver the message to the procFunc on the
|
||||
// proc.procFuncCh, and we can then read that message from the procFuncCh in
|
||||
// the procFunc running.
|
||||
func procFuncHello(ctx context.Context, proc process, procFuncCh chan Message) error {
|
||||
func procFuncHelloSubscriber(ctx context.Context, proc process, procFuncCh chan Message) error {
|
||||
// sayHelloNodes := make(map[Node]struct{})
|
||||
|
||||
for {
|
||||
|
|
Loading…
Reference in a new issue