Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

0.2.0 #12

Merged
merged 9 commits into from
Apr 25, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
45 changes: 0 additions & 45 deletions .github/workflows/build-and-release.yml

This file was deleted.

3 changes: 1 addition & 2 deletions .github/workflows/check-pr.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,7 @@ name: Check PR
on:
workflow_dispatch:
pull_request:
branches: [ master ]

branches-ignore: []
jobs:

goreleaser:
Expand Down
18 changes: 3 additions & 15 deletions .goreleaser.yml
Original file line number Diff line number Diff line change
Expand Up @@ -30,22 +30,10 @@ archives:
files:
- none*
name_template: '{{ .ProjectName }}_v{{ .Version }}_{{ .Os }}_{{ .Arch }}'
checksum:
name_template: 'checksums.txt'
# signs:
# - artifacts: checksum
# args:
# # if you are using this is in a GitHub action or some other automated pipeline, you
# # need to pass the batch flag to indicate its not interactive.
# - "--batch"
# - "--local-user"
# - "{{ .Env.GPG_FINGERPRINT }}"
# - "--output"
# - "${signature}"
# - "--detach-sign"
# - "${artifact}"
# checksum:
# name_template: 'checksums.txt'
release:
draft: true
disable: true
# extra_files:
# - glob: ./docs.zip
# disable: true
Expand Down
17 changes: 7 additions & 10 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ Anklet is fairly lightweight. When running 2 `github` plugin services, we see co
### How does it manage VM Templates on the host?

Anklet handles VM [Templates/Tags](https://docs.veertu.com/anka/anka-virtualization-cli/getting-started/creating-vms/#vm-templates) the best it can using the Anka CLI.
- If the VM Template or Tag does not exist, Anklet will pull it from the Registry using the `default` configured registry under `anka registry list-repos`.
- If the VM Template or Tag does not exist, Anklet will pull it from the Registry using the `default` configured registry under `anka registry list-repos`. You can also set the `registry_url` in the `config.yml` to use a different registry.
- Two consecutive pulls cannot happen on the same host or else the data may become corrupt. If a second job is picked up that requires a pull, it will send it back to the queue so another host can handle it.
- If the Template *AND* Tag already exist, it does *not* issue a pull from the Registry (which therefore doesn't require maintaining a Registry at all; useful for users who use `anka export/import`). Important: You must define the tag, or else it will attempt to use "latest" and forcefully issue a pull.

Expand All @@ -62,6 +62,8 @@ Anklet handles VM [Templates/Tags](https://docs.veertu.com/anka/anka-virtualizat
registration: repo
repo: anklet
owner: veertuinc
registry_url: http://anka.registry:8089
sleep_interval: 10 # sleep 10 seconds between checks for new jobs
database:
enabled: true
url: localhost
Expand All @@ -75,6 +77,7 @@ Anklet handles VM [Templates/Tags](https://docs.veertu.com/anka/anka-virtualizat
registration: repo
repo: anklet
owner: veertuinc
registry_url: http://anka.registry:8089
database:
enabled: true
url: localhost
Expand All @@ -84,6 +87,7 @@ Anklet handles VM [Templates/Tags](https://docs.veertu.com/anka/anka-virtualizat
database: 0

```
> Note: You can only ever run two VMs per host per the Apple macOS SLA. While you can specify more than two services, only two will ever be running a VM at one time. `sleep_interval` can be used to control the frequency/priority of a service and increase the odds that a job will be picked up.
3. Run the daemon by executing `anklet` on the host that has the [Anka CLI installed](https://docs.veertu.com/anka/anka-virtualization-cli/getting-started/installing-the-anka-virtualization-package/).
- `tail -fF /Users/myUser/Library/Logs/anklet.log` to see the logs. You can run `anklet` with `LOG_LEVEL=DEBUG` to see more verbose output.
3. To stop, you have two options:
Expand Down Expand Up @@ -117,6 +121,7 @@ While you can run it anywhere you want, its likely going to be less latency to h
brew install go
go mod tidy
LOG_LEVEL=dev go run main.go
tail -fF ~/Library/Logs/anklet.log
```

The `dev` LOG_LEVEL has colored output with text + pretty printed JSON for easier debugging. Here is an example:
Expand Down Expand Up @@ -174,12 +179,4 @@ Each plugin must have a `{name}.go` file with a `Run` function that takes in `co
The `Run` function should be designed to run multiple times in parallel. It should not rely on any state from the previous runs.
- Always `return` out of `Run` so the sleep interval and main.go can handle the next run properly with new context. Never loop inside of the plugin code.
- Should never panic but instead throw an ERROR and return.
- It's critical that you check for context cancellation before important logic that could orphan resources.

TODO

- Developer guide for writing plugins
- Timeouts for pulls, etc
- Check for user cancellation (from github) and cleanup
- Output inner actions-runner/_diag log on failure
- support org level registration for github plugin
- It's critical that you check for context cancellation before important logic that could orphan resources.
13 changes: 10 additions & 3 deletions internal/anka/cli.go
Original file line number Diff line number Diff line change
Expand Up @@ -145,13 +145,20 @@ func (cli *Cli) AnkaRegistryPull(ctx context.Context, template string, tag strin
return fmt.Errorf("context canceled before AnkaRegistryPull")
}
logger := logging.GetLoggerFromContext(ctx)
logger.DebugContext(ctx, "pulling template to host")
service := config.GetServiceFromContext(ctx)
var registryExtra []string
if service.RegistryURL != "" {
registryExtra = []string{"--remote", service.RegistryURL}
}
var args []string
if tag != "(using latest)" {
args = []string{"anka", "-j", "registry", "pull", "--shrink", template, "--tag", tag}
args = append([]string{"anka", "-j", "registry"}, registryExtra...)
args = append(args, "pull", "--shrink", template, "--tag", tag)
} else {
args = []string{"anka", "-j", "registry", "pull", "--shrink", template}
args = append([]string{"anka", "-j", "registry"}, registryExtra...)
args = append(args, "pull", "--shrink", template)
}
logger.DebugContext(ctx, "pulling template to host")
pulledTemplate, err := cli.ExecuteParseJson(ctx, args...)
if err != nil {
return err
Expand Down
1 change: 1 addition & 0 deletions internal/config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ type Service struct {
Repo string `yaml:"repo"`
Owner string `yaml:"owner"`
Database Database `yaml:"database"`
RegistryURL string `yaml:"registry_url"`
}

func LoadConfig(configPath string) (*Config, error) {
Expand Down
3 changes: 2 additions & 1 deletion plugins/github/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,12 @@ In the `config.yml`, you can define the `github` plugin as follows:
services:
- name: RUNNER1
plugin: github
token: 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
token: github_pat_XXX
# can be org or repo
registration: repo
repo: anklet
owner: veertuinc
registry_url: http://anka.registry:8089
database:
enabled: true
url: localhost
Expand Down
21 changes: 13 additions & 8 deletions plugins/github/github.go
Original file line number Diff line number Diff line change
Expand Up @@ -405,6 +405,7 @@ func Run(ctx context.Context, logger *slog.Logger) {
}
if *currentJob.Status == "completed" {
jobCompleted = true
ctx = logging.AppendCtx(ctx, slog.String("conclusion", *currentJob.Conclusion))
logger.InfoContext(ctx, "job completed", "job_id", *workflowRunJob.Job.ID)
} else if logCounter%2 == 0 {
if ctx.Err() != nil {
Expand Down Expand Up @@ -451,14 +452,7 @@ func removeSelfHostedRunner(ctx context.Context, vm anka.VM, workflowRunID int64
"ankaTemplateTag": "(using latest)",
"err": "DELETE https://api.github.com/repos/veertuinc/anklet/actions/runners/142: 422 Bad request - Runner \"anklet-vm-\u003cuuid\u003e\" is still running a job\" []",
*/
cancelResponse, _, cancelErr := ExecuteGitHubClientFunction[github.Response](ctx, logger, func() (*github.Response, *github.Response, error) {
resp, err := githubClient.Actions.CancelWorkflowRunByID(ctx, service.Owner, service.Repo, workflowRunID)
return resp, nil, err
})
if cancelErr != nil || cancelResponse.Response.StatusCode != 202 {
logger.ErrorContext(ctx, "error executing githubClient.Actions.CancelWorkflowRunByID", "err", cancelErr, "response", cancelResponse)
return
}
cancelSent := false
for {
workflowRun, _, err := ExecuteGitHubClientFunction[github.WorkflowRun](ctx, logger, func() (*github.WorkflowRun, *github.Response, error) {
workflowRun, resp, err := githubClient.Actions.GetWorkflowRunByID(context.Background(), service.Owner, service.Repo, workflowRunID)
Expand All @@ -472,6 +466,17 @@ func removeSelfHostedRunner(ctx context.Context, vm anka.VM, workflowRunID int64
break
} else {
logger.WarnContext(ctx, "workflow run is still active... waiting for cancellation so we can clean up the runner...", "workflow_run_id", workflowRunID)
if !cancelSent { // this has to happen here so that it doesn't error with "409 Cannot cancel a workflow run that is completed. " if the job is already cancelled
cancelResponse, _, cancelErr := ExecuteGitHubClientFunction[github.Response](ctx, logger, func() (*github.Response, *github.Response, error) {
resp, err := githubClient.Actions.CancelWorkflowRunByID(ctx, service.Owner, service.Repo, workflowRunID)
return resp, nil, err
})
if cancelErr != nil || cancelResponse.Response.StatusCode != 202 {
logger.ErrorContext(ctx, "error executing githubClient.Actions.CancelWorkflowRunByID", "err", cancelErr, "response", cancelResponse)
break
}
cancelSent = true
}
time.Sleep(20 * time.Second)
}
}
Expand Down
Loading