Skip to content

Commit

Permalink
feat: impl checkout on exec action
Browse files Browse the repository at this point in the history
  • Loading branch information
adityathebe committed Oct 17, 2023
1 parent 6921cf5 commit deb6f30
Show file tree
Hide file tree
Showing 10 changed files with 224 additions and 21 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -20,3 +20,4 @@ postgres-db/
ui/scripts/
Chart.lock
chart/charts/
.downloads
3 changes: 3 additions & 0 deletions api/v1/checks.go
Original file line number Diff line number Diff line change
Expand Up @@ -974,6 +974,9 @@ type GitCheckout struct {
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"`
// Destination is the full path to where the contents of the URL should be downloaded to.
// If left empty, the sha256 hash of the URL will be used as the dir name.
Destination string `yaml:"destination,omitempty" json:"destination,omitempty"`
}

type ExecCheck struct {
Expand Down
85 changes: 64 additions & 21 deletions checks/exec.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,9 @@ import (
"github.com/flanksource/canary-checker/api/external"
v1 "github.com/flanksource/canary-checker/api/v1"
"github.com/flanksource/canary-checker/pkg"
"github.com/flanksource/commons/files"
"github.com/flanksource/commons/hash"
"github.com/flanksource/commons/logger"
"github.com/flanksource/duty/types"
)

type ExecChecker struct {
Expand All @@ -41,26 +42,65 @@ func (c *ExecChecker) Run(ctx *context.Context) pkg.Results {
return results
}

func (c *ExecChecker) Check(ctx *context.Context, extConfig external.Check) pkg.Results {
check := extConfig.(v1.ExecCheck)
for i, env := range check.EnvVars {
type execEnv struct {
envs []string
mountPoint string
}

func (c *ExecChecker) prepareEnvironment(ctx *context.Context, check v1.ExecCheck) (*execEnv, error) {
var result execEnv

for _, 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)}
return nil, fmt.Errorf("error fetching env value (name=%s): %w", env.Name, err)
}

result.envs = append(result.envs, fmt.Sprintf("%s=%s", env.Name, val))
}

if check.Checkout != nil {
if connection, err := ctx.HydrateConnectionByURL(check.Checkout.Connection); err != nil {
return nil, fmt.Errorf("error hydrating connection: %w", err)
} else if connection != nil {
check.Checkout.URL = connection.URL
}

if check.Checkout.URL == "" {
return nil, fmt.Errorf("error checking out. missing URL")
}

result.mountPoint = check.Checkout.Destination
if check.Checkout.Destination == "" {
pwd, _ := os.Getwd()
result.mountPoint = filepath.Join(pwd, ".downloads", hash.Sha256Hex(check.Checkout.URL))
}

if err := files.Getter(check.Checkout.URL, result.mountPoint); err != nil {
return nil, fmt.Errorf("error checking out %s: %w", check.Checkout.URL, err)
}
}

check.EnvVars[i].ValueStatic = val
return &result, nil
}

func (c *ExecChecker) Check(ctx *context.Context, extConfig external.Check) pkg.Results {
check := extConfig.(v1.ExecCheck)

env, err := c.prepareEnvironment(ctx, check)
if err != nil {
return []*pkg.CheckResult{pkg.Fail(check, ctx.Canary).Failf("something went wrong while preparing exec env: %v", err)}
}

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

func execPowershell(ctx *context.Context, check v1.ExecCheck) pkg.Results {
func execPowershell(ctx *context.Context, check v1.ExecCheck, envParams *execEnv) pkg.Results {
result := pkg.Success(check, ctx.Canary)
ps, err := osExec.LookPath("powershell.exe")
if err != nil {
Expand All @@ -69,19 +109,31 @@ func execPowershell(ctx *context.Context, check v1.ExecCheck) pkg.Results {

args := []string{check.Script}
cmd := osExec.CommandContext(ctx, ps, args...)
cmd.Env = append(os.Environ(), envVarSlice(check.EnvVars)...)
if len(envParams.envs) != 0 {
cmd.Env = append(os.Environ(), envParams.envs...)
}
if envParams.mountPoint != "" {
cmd.Dir = envParams.mountPoint
}

return runCmd(cmd, result)
}

func execBash(ctx *context.Context, check v1.ExecCheck) pkg.Results {
func execBash(ctx *context.Context, check v1.ExecCheck, envParams *execEnv) 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 len(envParams.envs) != 0 {
cmd.Env = append(os.Environ(), envParams.envs...)
}
if envParams.mountPoint != "" {
cmd.Dir = envParams.mountPoint
}

if err := setupConnection(ctx, check, cmd); err != nil {
return []*pkg.CheckResult{result.Failf("failed to setup connection: %v", err)}
}
Expand Down Expand Up @@ -188,15 +240,6 @@ 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
3 changes: 3 additions & 0 deletions config/deploy/crd.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -2138,6 +2138,9 @@ spec:
type: object
connection:
type: string
destination:
description: Destination is the full path to where the contents of the URL should be downloaded to. If left empty, the sha256 hash of the URL will be used as the dir name.
type: string
password:
properties:
name:
Expand Down
126 changes: 126 additions & 0 deletions config/deploy/manifests.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -2105,6 +2105,101 @@ 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
destination:
description: Destination is the full path to where the contents of the URL should be downloaded to. If left empty, the sha256 hash of the URL will be used as the dir name.
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 +2419,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
3 changes: 3 additions & 0 deletions config/schemas/canary.schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -1585,6 +1585,9 @@
},
"certificate": {
"$ref": "#/$defs/EnvVar"
},
"destination": {
"type": "string"
}
},
"additionalProperties": false,
Expand Down
3 changes: 3 additions & 0 deletions config/schemas/component.schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -1797,6 +1797,9 @@
},
"certificate": {
"$ref": "#/$defs/EnvVar"
},
"destination": {
"type": "string"
}
},
"additionalProperties": false,
Expand Down
3 changes: 3 additions & 0 deletions config/schemas/health_exec.schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -197,6 +197,9 @@
},
"certificate": {
"$ref": "#/$defs/EnvVar"
},
"destination": {
"type": "string"
}
},
"additionalProperties": false,
Expand Down
3 changes: 3 additions & 0 deletions config/schemas/topology.schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -1767,6 +1767,9 @@
},
"certificate": {
"$ref": "#/$defs/EnvVar"
},
"destination": {
"type": "string"
}
},
"additionalProperties": false,
Expand Down
15 changes: 15 additions & 0 deletions fixtures/minimal/exec_checkout.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
apiVersion: canaries.flanksource.com/v1
kind: Canary
metadata:
name: exec-checkout
spec:
interval: 30
exec:
- name: exec-checkout
description: "exec with git"
script: |
cat go.mod | head -n 1
checkout:
url: github.com/flanksource/duty
test:
expr: 'results.stdout == "module github.com/flanksource/duty"'

0 comments on commit deb6f30

Please sign in to comment.