initial commit
This commit is contained in:
154
actions/actions.go
Normal file
154
actions/actions.go
Normal file
@@ -0,0 +1,154 @@
|
|||||||
|
package actions
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"sort"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
type OptionMissingError struct {
|
||||||
|
optionName string
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o OptionMissingError) Error() string {
|
||||||
|
return fmt.Sprintf("Error during config parsing: option %s could not be parsed.", o.optionName)
|
||||||
|
}
|
||||||
|
|
||||||
|
type Options map[string]interface{}
|
||||||
|
|
||||||
|
type ActionConfig struct {
|
||||||
|
Type string `json:"type"`
|
||||||
|
Options Options `json:"options"`
|
||||||
|
Stage int `json:"stage"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type KillSwitchConfig struct {
|
||||||
|
Name string `json:"name"`
|
||||||
|
Type string `json:"type"`
|
||||||
|
Options Options `json:"options"`
|
||||||
|
Actions []ActionConfig `json:"actions"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type Action interface {
|
||||||
|
Execute()
|
||||||
|
}
|
||||||
|
|
||||||
|
type Printer struct {
|
||||||
|
Message string
|
||||||
|
ActionChan chan bool
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p Printer) Execute() {
|
||||||
|
fmt.Printf("Print action fires. Message: %s", p.Message)
|
||||||
|
p.ActionChan <- true
|
||||||
|
}
|
||||||
|
|
||||||
|
type TimeOut struct {
|
||||||
|
Duration time.Duration
|
||||||
|
ActionChan chan bool
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t TimeOut) Execute() {
|
||||||
|
fmt.Printf("Waiting %d seconds\n", t.Duration/time.Second)
|
||||||
|
time.Sleep(t.Duration)
|
||||||
|
t.ActionChan <- true
|
||||||
|
}
|
||||||
|
|
||||||
|
type Stage struct {
|
||||||
|
Actions []Action
|
||||||
|
}
|
||||||
|
|
||||||
|
type StagedActions struct {
|
||||||
|
ActionChan chan bool
|
||||||
|
StageCount int
|
||||||
|
Stages []Stage
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a StagedActions) Execute() {
|
||||||
|
for idx, stage := range a.Stages {
|
||||||
|
if idx < a.StageCount {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Printf("Execute Stage %v\n", idx+1)
|
||||||
|
for actionidx, _ := range stage.Actions {
|
||||||
|
go stage.Actions[actionidx].Execute()
|
||||||
|
}
|
||||||
|
|
||||||
|
for range stage.Actions {
|
||||||
|
<-a.ActionChan
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewPrint(config ActionConfig, c chan bool) (Action, error) {
|
||||||
|
opts := config.Options
|
||||||
|
message, ok := opts["message"]
|
||||||
|
|
||||||
|
if !ok {
|
||||||
|
return nil, OptionMissingError{"message"}
|
||||||
|
}
|
||||||
|
|
||||||
|
return Printer{fmt.Sprintf("%v", message), c}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewTimeOut(config ActionConfig, c chan bool) (Action, error) {
|
||||||
|
opts := config.Options
|
||||||
|
duration, ok := opts["duration"]
|
||||||
|
|
||||||
|
if !ok {
|
||||||
|
return nil, OptionMissingError{"message"}
|
||||||
|
}
|
||||||
|
|
||||||
|
return TimeOut{time.Duration(duration.(float64)) * time.Second, c}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewSingleAction(config ActionConfig, c chan bool) (Action, error) {
|
||||||
|
if config.Type == "Print" {
|
||||||
|
return NewPrint(config, c)
|
||||||
|
}
|
||||||
|
|
||||||
|
if config.Type == "TimeOut" {
|
||||||
|
return NewTimeOut(config, c)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil, fmt.Errorf("Error parsing config: Action with type %s does not exists", config.Type)
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewAction(config []ActionConfig) (Action, error) {
|
||||||
|
if len(config) == 1 {
|
||||||
|
return NewSingleAction(config[0], make(chan bool))
|
||||||
|
}
|
||||||
|
|
||||||
|
sort.Slice(config, func(i, j int) bool {
|
||||||
|
return config[i].Stage < config[j].Stage
|
||||||
|
})
|
||||||
|
|
||||||
|
stagedActions := StagedActions{make(chan bool), 0, []Stage{}}
|
||||||
|
|
||||||
|
stageMap := make(map[int][]Action)
|
||||||
|
|
||||||
|
for _, actionCfg := range config {
|
||||||
|
newAction, err := NewSingleAction(actionCfg, stagedActions.ActionChan)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
val, exists := stageMap[actionCfg.Stage]
|
||||||
|
|
||||||
|
if !exists {
|
||||||
|
stageMap[actionCfg.Stage] = []Action{newAction}
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
stageMap[actionCfg.Stage] = append(val, newAction)
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, value := range stageMap {
|
||||||
|
stagedActions.Stages = append(stagedActions.Stages, Stage{value})
|
||||||
|
}
|
||||||
|
|
||||||
|
return stagedActions, nil
|
||||||
|
//return Action{}, fmt.Errorf("Error parsing config: Action with type %s does not exists", config.Type)
|
||||||
|
}
|
||||||
117
gokill.go
Normal file
117
gokill.go
Normal file
@@ -0,0 +1,117 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"flag"
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"unknown.com/gokill/triggers"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
configFile := flag.String("c", "", "path to config file")
|
||||||
|
flag.Parse()
|
||||||
|
|
||||||
|
if *configFile == "" {
|
||||||
|
fmt.Println("No config file given. Use --help to show usage.")
|
||||||
|
//return
|
||||||
|
}
|
||||||
|
|
||||||
|
b := []byte(`
|
||||||
|
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"type": "TimeOut",
|
||||||
|
"name": "custom timeout",
|
||||||
|
"options": {
|
||||||
|
"duration": 5
|
||||||
|
},
|
||||||
|
"actions": [
|
||||||
|
{
|
||||||
|
"type": "TimeOut",
|
||||||
|
"options": {
|
||||||
|
"duration": 4
|
||||||
|
},
|
||||||
|
"stage": 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "Print",
|
||||||
|
"options": {
|
||||||
|
"message": "shutdown -h now"
|
||||||
|
},
|
||||||
|
"stage": 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "Print",
|
||||||
|
"options": {
|
||||||
|
"message": "shutdown -h now"
|
||||||
|
},
|
||||||
|
"stage": 2
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "TimeOut",
|
||||||
|
"options": {
|
||||||
|
"duration": 4
|
||||||
|
},
|
||||||
|
"stage": 5
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "Print",
|
||||||
|
"options": {
|
||||||
|
"message": "shutdown -h now"
|
||||||
|
},
|
||||||
|
"stage": 4
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "Print",
|
||||||
|
"options": {
|
||||||
|
"message": "shutdown -h now"
|
||||||
|
},
|
||||||
|
"stage": 7
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
`)
|
||||||
|
|
||||||
|
var f []triggers.KillSwitchConfig
|
||||||
|
err := json.Unmarshal(b, &f)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
trigger, err := triggers.NewTrigger(f[0])
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
fmt.Println(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
trigger.Listen()
|
||||||
|
|
||||||
|
//stagedActions := actions.StagedActions{make(chan bool), 0, []actions.Stage{}}
|
||||||
|
|
||||||
|
//stageOne := actions.Stage{[]actions.Action{
|
||||||
|
// actions.Printer{"first action\n", stagedActions.ActionChan},
|
||||||
|
// actions.Printer{"second actiloo\n", stagedActions.ActionChan},
|
||||||
|
// actions.TimeOut{stagedActions.ActionChan},
|
||||||
|
//}}
|
||||||
|
|
||||||
|
//stageTwo := actions.Stage{[]actions.Action{
|
||||||
|
// actions.Printer{"third action\n", stagedActions.ActionChan},
|
||||||
|
// actions.TimeOut{stagedActions.ActionChan},
|
||||||
|
//}}
|
||||||
|
|
||||||
|
//stageThree := actions.Stage{[]actions.Action{
|
||||||
|
// actions.Printer{"four action\n", stagedActions.ActionChan},
|
||||||
|
// actions.Printer{"five action\n", stagedActions.ActionChan},
|
||||||
|
// actions.Printer{"six action\n", stagedActions.ActionChan},
|
||||||
|
//}}
|
||||||
|
|
||||||
|
//stagedActions.Stages = []actions.Stage{stageOne, stageTwo, stageThree}
|
||||||
|
|
||||||
|
//timeOut := triggers.NewTimeOut(2*time.Second, stagedActions)
|
||||||
|
//timeOut.Listen()
|
||||||
|
}
|
||||||
68
triggers/triggers.go
Normal file
68
triggers/triggers.go
Normal file
@@ -0,0 +1,68 @@
|
|||||||
|
package triggers
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"unknown.com/gokill/actions"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Options map[string]interface{}
|
||||||
|
|
||||||
|
type KillSwitchConfig struct {
|
||||||
|
Name string `json:"name"`
|
||||||
|
Type string `json:"type"`
|
||||||
|
Options Options `json:"options"`
|
||||||
|
Actions []actions.ActionConfig `json:"actions"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type Trigger interface {
|
||||||
|
Listen()
|
||||||
|
}
|
||||||
|
|
||||||
|
type TimeOut struct {
|
||||||
|
d time.Duration
|
||||||
|
action actions.Action
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t TimeOut) Listen() {
|
||||||
|
fmt.Println("TimeOut listens")
|
||||||
|
time.Sleep(t.d)
|
||||||
|
fmt.Println("TimeOut fires")
|
||||||
|
t.action.Execute()
|
||||||
|
}
|
||||||
|
|
||||||
|
type OptionMissingError struct {
|
||||||
|
optionName string
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o OptionMissingError) Error() string {
|
||||||
|
return fmt.Sprintf("Error during config parsing: option %s could not be parsed.", o.optionName)
|
||||||
|
}
|
||||||
|
|
||||||
|
// func NewTimeOut(d time.Duration, action actions.Action) TimeOut {
|
||||||
|
func NewTimeOut(config KillSwitchConfig) (TimeOut, error) {
|
||||||
|
opts := config.Options
|
||||||
|
|
||||||
|
duration, ok := opts["duration"]
|
||||||
|
|
||||||
|
if !ok {
|
||||||
|
return TimeOut{}, OptionMissingError{"duration"}
|
||||||
|
}
|
||||||
|
|
||||||
|
action, err := actions.NewAction(config.Actions)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return TimeOut{}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return TimeOut{time.Duration(duration.(float64)) * time.Second, action}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewTrigger(config KillSwitchConfig) (Trigger, error) {
|
||||||
|
if config.Type == "TimeOut" {
|
||||||
|
return NewTimeOut(config)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil, fmt.Errorf("Error parsing config: Trigger with type %s does not exists", config.Type)
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user