Skip to content

Commit

Permalink
feat: add support for env vars in exec check
Browse files Browse the repository at this point in the history
  • Loading branch information
adityathebe committed Oct 17, 2023
1 parent 8eb06ec commit 6921cf5
Show file tree
Hide file tree
Showing 9 changed files with 345 additions and 19 deletions.
12 changes: 12 additions & 0 deletions api/v1/checks.go
Original file line number Diff line number Diff line change
Expand Up @@ -968,13 +968,25 @@ type ExecConnections struct {
Azure *AzureConnection `yaml:"azure,omitempty" json:"azure,omitempty"`
}

type GitCheckout struct {
URL string `yaml:"url,omitempty" json:"url,omitempty"`
Connection string `yaml:"connection,omitempty" json:"connection,omitempty"`
Username types.EnvVar `yaml:"username,omitempty" json:"username,omitempty"`
Password types.EnvVar `yaml:"password,omitempty" json:"password,omitempty"`
Certificate types.EnvVar `yaml:"certificate,omitempty" json:"certificate,omitempty"`
}

type ExecCheck struct {
Description `yaml:",inline" json:",inline"`
Templatable `yaml:",inline" json:",inline"`
// Script can be a inline script or a path to a script that needs to be executed
// On windows executed via powershell and in darwin and linux executed using bash
Script string `yaml:"script" json:"script"`
Connections ExecConnections `yaml:"connections,omitempty" json:"connections,omitempty"`
// EnvVars are the environment variables that are accesible to exec processes
EnvVars []types.EnvVar `yaml:"env,omitempty" json:"env,omitempty"`
// Checkout details the git repository that should be mounted to the process
Checkout *GitCheckout `yaml:"checkout,omitempty" json:"checkout,omitempty"`
}

func (c ExecCheck) GetType() string {
Expand Down
30 changes: 30 additions & 0 deletions api/v1/zz_generated.deepcopy.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

61 changes: 42 additions & 19 deletions checks/exec.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import (
v1 "github.com/flanksource/canary-checker/api/v1"
"github.com/flanksource/canary-checker/pkg"
"github.com/flanksource/commons/logger"
"github.com/flanksource/duty/types"
)

type ExecChecker struct {
Expand All @@ -36,27 +37,55 @@ func (c *ExecChecker) Run(ctx *context.Context) pkg.Results {
for _, conf := range ctx.Canary.Spec.Exec {
results = append(results, c.Check(ctx, conf)...)
}

return results
}

func (c *ExecChecker) Check(ctx *context.Context, extConfig external.Check) pkg.Results {
check := extConfig.(v1.ExecCheck)
for i, env := range check.EnvVars {
val, err := ctx.GetEnvValueFromCache(env)
if err != nil {
return []*pkg.CheckResult{pkg.Fail(check, ctx.Canary).Failf("error fetching env value (name=%s): %v", env.Name, err)}
}

check.EnvVars[i].ValueStatic = val
}

switch runtime.GOOS {
case "windows":
return execPowershell(check, ctx)
return execPowershell(ctx, check)
default:
return execBash(check, ctx)
return execBash(ctx, check)
}
}

func execPowershell(check v1.ExecCheck, ctx *context.Context) pkg.Results {
func execPowershell(ctx *context.Context, check v1.ExecCheck) pkg.Results {
result := pkg.Success(check, ctx.Canary)
ps, err := osExec.LookPath("powershell.exe")
if err != nil {
result.Failf("powershell not found")
}

args := []string{check.Script}
cmd := osExec.Command(ps, args...)
cmd := osExec.CommandContext(ctx, ps, args...)
cmd.Env = append(os.Environ(), envVarSlice(check.EnvVars)...)
return runCmd(cmd, result)
}

func execBash(ctx *context.Context, check v1.ExecCheck) pkg.Results {
result := pkg.Success(check, ctx.Canary)
fields := strings.Fields(check.Script)
if len(fields) == 0 {
return []*pkg.CheckResult{result.Failf("no script provided")}
}

cmd := osExec.CommandContext(ctx, "bash", "-c", check.Script)
cmd.Env = append(os.Environ(), envVarSlice(check.EnvVars)...)
if err := setupConnection(ctx, check, cmd); err != nil {
return []*pkg.CheckResult{result.Failf("failed to setup connection: %v", err)}
}

return runCmd(cmd, result)
}

Expand Down Expand Up @@ -117,21 +146,6 @@ func setupConnection(ctx *context.Context, check v1.ExecCheck, cmd *osExec.Cmd)
return nil
}

func execBash(check v1.ExecCheck, ctx *context.Context) pkg.Results {
result := pkg.Success(check, ctx.Canary)
fields := strings.Fields(check.Script)
if len(fields) == 0 {
return []*pkg.CheckResult{result.Failf("no script provided")}
}

cmd := osExec.Command("bash", "-c", check.Script)
if err := setupConnection(ctx, check, cmd); err != nil {
return []*pkg.CheckResult{result.Failf("failed to setup connection: %v", err)}
}

return runCmd(cmd, result)
}

func runCmd(cmd *osExec.Cmd, result *pkg.CheckResult) (results pkg.Results) {
var stdout bytes.Buffer
var stderr bytes.Buffer
Expand Down Expand Up @@ -174,6 +188,15 @@ func saveConfig(configTemplate *textTemplate.Template, view any) (string, error)
return configPath, nil
}

func envVarSlice(envs []types.EnvVar) []string {
result := make([]string, len(envs))
for i, env := range envs {
result[i] = fmt.Sprintf("%s=%s", env.Name, env.ValueStatic)
}

return result
}

var (
awsConfigTemplate *textTemplate.Template
gcloudConfigTemplate *textTemplate.Template
Expand Down
123 changes: 123 additions & 0 deletions config/deploy/crd.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -2105,6 +2105,98 @@ spec:
exec:
items:
properties:
checkout:
description: Checkout details the git repository that should be mounted to the process
properties:
certificate:
properties:
name:
type: string
value:
type: string
valueFrom:
properties:
configMapKeyRef:
properties:
key:
type: string
name:
type: string
required:
- key
type: object
secretKeyRef:
properties:
key:
type: string
name:
type: string
required:
- key
type: object
type: object
type: object
connection:
type: string
password:
properties:
name:
type: string
value:
type: string
valueFrom:
properties:
configMapKeyRef:
properties:
key:
type: string
name:
type: string
required:
- key
type: object
secretKeyRef:
properties:
key:
type: string
name:
type: string
required:
- key
type: object
type: object
type: object
url:
type: string
username:
properties:
name:
type: string
value:
type: string
valueFrom:
properties:
configMapKeyRef:
properties:
key:
type: string
name:
type: string
required:
- key
type: object
secretKeyRef:
properties:
key:
type: string
name:
type: string
required:
- key
type: object
type: object
type: object
type: object
connections:
properties:
aws:
Expand Down Expand Up @@ -2324,6 +2416,37 @@ spec:
template:
type: string
type: object
env:
description: EnvVars are the environment variables that are accesible to exec processes
items:
properties:
name:
type: string
value:
type: string
valueFrom:
properties:
configMapKeyRef:
properties:
key:
type: string
name:
type: string
required:
- key
type: object
secretKeyRef:
properties:
key:
type: string
name:
type: string
required:
- key
type: object
type: object
type: object
type: array
icon:
description: Icon for overwriting default icon on the dashboard
type: string
Expand Down
30 changes: 30 additions & 0 deletions config/schemas/canary.schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -1394,6 +1394,15 @@
},
"connections": {
"$ref": "#/$defs/ExecConnections"
},
"env": {
"items": {
"$ref": "#/$defs/EnvVar"
},
"type": "array"
},
"checkout": {
"$ref": "#/$defs/GitCheckout"
}
},
"additionalProperties": false,
Expand Down Expand Up @@ -1560,6 +1569,27 @@
"instance"
]
},
"GitCheckout": {
"properties": {
"url": {
"type": "string"
},
"connection": {
"type": "string"
},
"username": {
"$ref": "#/$defs/EnvVar"
},
"password": {
"$ref": "#/$defs/EnvVar"
},
"certificate": {
"$ref": "#/$defs/EnvVar"
}
},
"additionalProperties": false,
"type": "object"
},
"GitHubCheck": {
"properties": {
"description": {
Expand Down
Loading

0 comments on commit 6921cf5

Please sign in to comment.