Skip to content

Commit

Permalink
Separate out Windows so all builds work
Browse files Browse the repository at this point in the history
  • Loading branch information
jdotjdot committed May 20, 2022
1 parent 31dcafa commit 87f58ed
Show file tree
Hide file tree
Showing 6 changed files with 238 additions and 234 deletions.
7 changes: 4 additions & 3 deletions cmd/configure.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,11 @@ package cmd
import (
"encoding/json"
"fmt"
"github.com/spf13/cobra"
"github.com/spf13/viper"
"io/ioutil"
"os"

"github.com/spf13/cobra"
"github.com/spf13/viper"
)

type ConfigFile struct {
Expand Down Expand Up @@ -113,7 +114,7 @@ Example setting common exclude text for use with 'cronitor discover':
if ioutil.WriteFile(configFilePath(), b, 0644) != nil {
fmt.Fprintf(os.Stderr,
"\nERROR: The configuration file %s could not be written; check permissions and try again. "+
"\n By default, configuration files are system-wide for ease of use in cron jobs and scripts. Specify an alternate config file using the --config argument or CRONITOR_CONFIG environment variable.\n\n", configFilePath())
"\n By default, configuration files are system-wide for ease of use in cron jobs and scripts. Specify an alternate config file using the --config argument or CRONITOR_CONFIG environment variable.\n\n", configFilePath())
os.Exit(126)
}
},
Expand Down
207 changes: 0 additions & 207 deletions cmd/discover.go
Original file line number Diff line number Diff line change
@@ -1,12 +1,8 @@
package cmd

import (
"crypto/sha256"
"encoding/hex"
"encoding/json"
"errors"
"fmt"
"github.com/capnspacehook/taskmaster"
"github.com/cronitorio/cronitor-cli/lib"
"github.com/manifoldco/promptui"
"github.com/spf13/cobra"
Expand Down Expand Up @@ -209,209 +205,6 @@ func processDirectory(username, directory string) {
}
}

func getWindowsKey(taskName string) string {
const MonitorKeyLength = 12

h := sha256.New()
h.Write([]byte(taskName))
hashed := hex.EncodeToString(h.Sum(nil))
return hashed[:MonitorKeyLength]
}

type WrappedWindowsTask taskmaster.RegisteredTask

func NewWrappedWindowsTask(t taskmaster.RegisteredTask) WrappedWindowsTask {
w := WrappedWindowsTask(t)
return w
}

func (r WrappedWindowsTask) IsMicrosoftTask() bool {
return strings.HasPrefix(r.Path, "\\Microsoft\\")
}

func (r WrappedWindowsTask) GetCommandToRun() string {
var commands []string
for _, action := range r.Definition.Actions {

if action.GetType() != taskmaster.TASK_ACTION_EXEC {
// We only support actions of type Exec, not com, email, or message (which are deprecated)
continue
}

execAction := action.(taskmaster.ExecAction)

commands = append(commands, strings.TrimSpace(fmt.Sprintf("%s %s", execAction.Path, execAction.Args)))
}

return strings.Join(commands, " && ")
}

func processWindowsTaskScheduler() bool {
const CronitorWindowsPath = "C:\\Program Files\\cronitor.exe"

taskService, err := taskmaster.Connect()
if err != nil {
log(fmt.Sprintf("err: %v", err))
return false
}
defer taskService.Disconnect()
collection, err := taskService.GetRegisteredTasks()
if err != nil {
log(fmt.Sprintf("err: %v", err))
return false
}
defer collection.Release()

// Read crontab into map of Monitor structs
monitors := map[string]*lib.Monitor{}
monitorToRegisteredTask := map[string]taskmaster.RegisteredTask{}
for _, task := range collection {
t := NewWrappedWindowsTask(task)
// Skip all built-in tasks; users don't want to monitor those
if t.IsMicrosoftTask() {
continue
}

hostname, err := os.Hostname()
if err != nil {
log(fmt.Sprintf("err: %v", err))
}
// Windows Task Scheduler won't allow multiple tasks with the same name, so using
// the tasks' name should be safe. You also do not seem to be able to edit the name
// in Windows Task Scheduler, so this seems safe as the Key as well.
fullName := fmt.Sprintf("%s/%s", hostname, task.Name)
// Max name length of 75, so we need to truncate
if len(fullName) >= 74 {
fullName = fullName[:74]
}
defaultName := fullName
tags := createTags()
key := getWindowsKey(fullName)
name := defaultName
skip := false

// The monitor name will always be the same, so we don't have to fetch it
// from the Cronitor existing monitors

if !isAutoDiscover {
fmt.Println(fmt.Sprintf("\n %s %s", defaultName, t.GetCommandToRun()))
for {
prompt := promptui.Prompt{
Label: "Job name",
Default: name,
//Validate: validateName,
AllowEdit: name != defaultName,
Templates: promptTemplates(),
}

if result, err := prompt.Run(); err == nil {
name = result
} else if err == promptui.ErrInterrupt {
printWarningText("Skipped", true)
skip = true
break
} else {
printErrorText("Error: "+err.Error()+"\n", false)
}

break
}
}

if skip {
continue
}

existingMonitors.AddName(name)

notificationListMap := map[string][]string{}
if notificationList != "" {
notificationListMap = map[string][]string{"templates": {notificationList}}
}

monitor := lib.Monitor{
DefaultName: defaultName,
Key: key,
Rules: []lib.Rule{},
Platform: lib.WINDOWS,
Tags: tags,
Type: "heartbeat",
Notifications: notificationListMap,
NoStdoutPassthru: noStdoutPassthru,
}
tz := effectiveTimezoneLocationName()
if tz.Name != "" {
monitor.Timezone = tz.Name
}

monitors[key] = &monitor
monitorToRegisteredTask[key] = task
}

printLn()

if len(monitors) > 0 {
printDoneText("Sending to Cronitor", true)
}

monitors, err = getCronitorApi().PutMonitors(monitors)
if err != nil {
fatal(err.Error(), 1)
}

if !dryRun && len(monitors) > 0 {
for key, task := range monitorToRegisteredTask {
newDefinition := task.Definition
// Clear out all existing actions on the new definition
newDefinition.Actions = []taskmaster.Action{}
var actionList []taskmaster.Action
for _, action := range task.Definition.Actions {
if action.GetType() != taskmaster.TASK_ACTION_EXEC {
// We only support actions of type Exec, not com, email, or message (which are deprecated)

fmt.Printf("not exec: %v", action)

// We don't want to delete the old actions
actionList = append(actionList, action)
continue
}

execAction := action.(taskmaster.ExecAction)

// If the action has already been converted to use cronitor.exe, then we
// don't need to modify it
// TODO: What if cronitor.exe has been renamed?
if strings.HasSuffix(strings.ToLower(execAction.Path), "cronitor.exe") {
actionList = append(actionList, action)
continue
}

actionList = append(actionList, taskmaster.ExecAction{
ID: execAction.ID,
Path: CronitorWindowsPath,
Args: strings.TrimSpace(fmt.Sprintf("exec %s %s %s", key, execAction.Path, execAction.Args)),
WorkingDir: execAction.WorkingDir,
})
}
for _, action := range actionList {
newDefinition.AddAction(action)
}

output, _ := json.Marshal(newDefinition)
log(fmt.Sprintf("%s: %s", task.Path, output))

newTask, err := taskService.UpdateTask(task.Path, newDefinition)
if err != nil {
serialized, _ := json.Marshal(newTask)
log(fmt.Sprintf("err updating task %s: %v. JSON: %s", task.Path, err, serialized))
printWarningText(fmt.Sprintf("Could not update task %s to automatically ping Cronitor. Error: `%s`", task.Name, err), true)
}
}
}

return len(monitors) > 0
}

func processCrontab(crontab *lib.Crontab) bool {
defer printLn()
printSuccessText(fmt.Sprintf("Checking %s", crontab.DisplayName()), false)
Expand Down
12 changes: 12 additions & 0 deletions cmd/discover_logic_other.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
//go:build !windows
// +build !windows

// This file provides stubs for Windows-only functions that will not be called on non-Windows architectures.
// Any function from here used in other files should be surrounded by:
// if runtime.GOOS == "windows" { }

package cmd

func processWindowsTaskScheduler() bool {
return false
}
Loading

0 comments on commit 87f58ed

Please sign in to comment.