-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #5 from uitml/golang-redux
Switch to Go
- Loading branch information
Showing
23 changed files
with
1,242 additions
and
44 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
root = true | ||
|
||
[*] | ||
charset = utf-8 | ||
indent_style = space | ||
insert_final_newline = true | ||
tab_width = 2 | ||
|
||
[*.go] | ||
indent_style = tab | ||
tab_width = 4 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
name: Release | ||
|
||
on: | ||
push: | ||
tags: | ||
- "v*" | ||
|
||
jobs: | ||
goreleaser: | ||
runs-on: ubuntu-latest | ||
steps: | ||
- name: Checkout | ||
uses: actions/checkout@v2 | ||
with: | ||
fetch_depth: 0 | ||
|
||
- name: Set up Go | ||
uses: actions/setup-go@v2 | ||
with: | ||
go-version: 1.14 | ||
|
||
- name: Run GoReleaser | ||
uses: goreleaser/goreleaser-action@v2 | ||
with: | ||
version: latest | ||
args: release | ||
env: | ||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1 +1,10 @@ | ||
# Platform. | ||
.DS_Store | ||
|
||
# Generic. | ||
.vscode/ | ||
.envrc | ||
|
||
# Project. | ||
/dist/ | ||
/out/ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,35 @@ | ||
project_name: frink | ||
|
||
before: | ||
hooks: | ||
- go mod tidy | ||
- go mod download | ||
|
||
release: | ||
prerelease: auto | ||
|
||
builds: | ||
- env: | ||
- CGO_ENABLED=0 | ||
goos: | ||
- darwin | ||
- linux | ||
goarch: | ||
- amd64 | ||
|
||
archives: | ||
- format: binary | ||
name_template: '{{ .ProjectName }}_{{ .Os }}_{{ .Arch }}' | ||
replacements: | ||
darwin: macOS | ||
linux: Linux | ||
amd64: x86_64 | ||
|
||
checksum: | ||
name_template: 'checksums.txt' | ||
|
||
snapshot: | ||
name_template: '{{ replace .Tag "v" "" }}-{{ .ShortCommit }}' | ||
|
||
changelog: | ||
skip: true |
This file was deleted.
Oops, something went wrong.
This file was deleted.
Oops, something went wrong.
This file was deleted.
Oops, something went wrong.
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,121 @@ | ||
package cmd | ||
|
||
import ( | ||
"fmt" | ||
"os" | ||
"strings" | ||
"text/tabwriter" | ||
"time" | ||
|
||
"github.com/dustin/go-humanize" | ||
"github.com/hako/durafmt" | ||
"github.com/spf13/cobra" | ||
batchv1 "k8s.io/api/batch/v1" | ||
) | ||
|
||
var showAll bool | ||
|
||
var listCmd = &cobra.Command{ | ||
Use: "ls", | ||
Short: "List jobs", | ||
|
||
RunE: func(cmd *cobra.Command, args []string) error { | ||
jobs, err := kubectx.ListJobs() | ||
if err != nil { | ||
return fmt.Errorf("could not list jobs: %w", err) | ||
} | ||
|
||
w := tabwriter.NewWriter(os.Stdout, 0, 0, 3, ' ', 0) | ||
defer w.Flush() | ||
|
||
fmt.Fprintln(w, header()) | ||
for _, job := range jobs.Items { | ||
fmt.Fprintln(w, row(job)) | ||
} | ||
|
||
return nil | ||
}, | ||
} | ||
|
||
func init() { | ||
rootCmd.AddCommand(listCmd) | ||
|
||
flags := listCmd.Flags() | ||
flags.BoolVarP(&showAll, "all", "a", false, "show all jobs; active and terminated") | ||
} | ||
|
||
var ( | ||
headerNames = []string{ | ||
"NAME", | ||
"STATUS", | ||
"COMPLETIONS", | ||
"DURATION", | ||
"AGE", | ||
} | ||
) | ||
|
||
func header() string { | ||
return strings.Join(headerNames, "\t") + "\t" | ||
} | ||
|
||
func row(job batchv1.Job) string { | ||
columns := []string{ | ||
job.Name, | ||
status(job), | ||
completions(job), | ||
duration(job), | ||
age(job), | ||
} | ||
|
||
return strings.Join(columns, "\t") + "\t" | ||
} | ||
|
||
func status(job batchv1.Job) string { | ||
switch { | ||
case job.Status.Active > 0: | ||
return "Active" | ||
case job.Spec.Completions == nil || *job.Spec.Completions == job.Status.Succeeded: | ||
return "Succeeded" | ||
case job.Status.Failed > 0: | ||
return "Failed" | ||
} | ||
|
||
return "Stopped" | ||
} | ||
|
||
func completions(job batchv1.Job) string { | ||
succeeded := job.Status.Succeeded | ||
total := succeeded + job.Status.Active + job.Status.Failed | ||
|
||
return fmt.Sprintf("%d/%d", succeeded, total) | ||
} | ||
|
||
func duration(job batchv1.Job) string { | ||
_, duration := timing(job) | ||
// TODO: Implement "smart" truncation scheme. | ||
humanized := durafmt.Parse(duration).LimitFirstN(2).String() | ||
|
||
return humanized | ||
} | ||
|
||
func age(job batchv1.Job) string { | ||
start, _ := timing(job) | ||
humanized := humanize.Time(start) | ||
|
||
return humanized | ||
} | ||
|
||
func timing(job batchv1.Job) (time.Time, time.Duration) { | ||
var start time.Time | ||
duration := time.Duration(0) | ||
if job.Status.StartTime != nil { | ||
start = job.Status.StartTime.Time | ||
end := time.Now() | ||
if job.Status.CompletionTime != nil { | ||
end = job.Status.CompletionTime.Time | ||
} | ||
duration = end.Sub(start) | ||
} | ||
|
||
return start, duration | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,52 @@ | ||
package cmd | ||
|
||
import ( | ||
"bufio" | ||
"errors" | ||
"fmt" | ||
"io" | ||
"os" | ||
|
||
"github.com/spf13/cobra" | ||
"github.com/uitml/frink/internal/k8s" | ||
) | ||
|
||
var logsCmd = &cobra.Command{ | ||
Use: "logs <name>", | ||
Short: "Fetch the logs of a job", | ||
|
||
RunE: func(cmd *cobra.Command, args []string) error { | ||
if len(args) == 0 { | ||
return fmt.Errorf("job name must be specified") | ||
} | ||
|
||
name := args[0] | ||
req, err := kubectx.GetJobLogs(name, k8s.DefaultLogOptions) | ||
if err != nil { | ||
return fmt.Errorf("unable to get logs: %w", errors.Unwrap(err)) | ||
} | ||
|
||
if req == nil { | ||
return fmt.Errorf("unable to get logs: request not returned (nil)") | ||
} | ||
|
||
stream, err := req.Stream() | ||
if err != nil { | ||
return fmt.Errorf("unable to stream logs: %w", err) | ||
} | ||
defer stream.Close() | ||
|
||
reader := bufio.NewReader(stream) | ||
if _, err := io.Copy(os.Stdout, reader); err != nil { | ||
return fmt.Errorf("unable to write output: %w", err) | ||
} | ||
|
||
return nil | ||
}, | ||
|
||
Aliases: []string{"watch"}, | ||
} | ||
|
||
func init() { | ||
rootCmd.AddCommand(logsCmd) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
package cmd | ||
|
||
import ( | ||
"fmt" | ||
|
||
"github.com/spf13/cobra" | ||
) | ||
|
||
var removeCmd = &cobra.Command{ | ||
Use: "rm <name>", | ||
Short: "Remove job from cluster", | ||
|
||
RunE: func(cmd *cobra.Command, args []string) error { | ||
if len(args) == 0 { | ||
return fmt.Errorf("job name must be specified") | ||
} | ||
|
||
name := args[0] | ||
if err := kubectx.DeleteJob(name); err != nil { | ||
return fmt.Errorf("unable to delete job: %w", err) | ||
} | ||
|
||
return nil | ||
}, | ||
} | ||
|
||
func init() { | ||
rootCmd.AddCommand(removeCmd) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,54 @@ | ||
// Package cmd provides implementations of CLI commands. | ||
package cmd | ||
|
||
import ( | ||
"fmt" | ||
"os" | ||
|
||
"github.com/spf13/cobra" | ||
"github.com/spf13/viper" | ||
"github.com/uitml/frink/internal/cli" | ||
"github.com/uitml/frink/internal/k8s" | ||
) | ||
|
||
// NOTE: Global package state; bad idea, but works for the time being. | ||
var kubectx *k8s.KubeContext | ||
|
||
var rootCmd = &cobra.Command{ | ||
Use: "frink", | ||
Short: "Frink simplifies your Springfield workflows", | ||
|
||
PersistentPreRunE: func(cmd *cobra.Command, args []string) error { | ||
context := viper.GetString("context") | ||
namespace := viper.GetString("namespace") | ||
|
||
ctx, err := k8s.Client(context, namespace) | ||
if err != nil { | ||
return fmt.Errorf("unable to get kube client: %w", err) | ||
} | ||
|
||
kubectx = ctx | ||
return nil | ||
}, | ||
|
||
// Do not display usage when an error occurs. | ||
SilenceUsage: true, | ||
} | ||
|
||
func init() { | ||
cobra.OnInitialize(cli.InitConfig) | ||
|
||
pflags := rootCmd.PersistentFlags() | ||
pflags.String("context", "", "name of the kubeconfig context to use") | ||
pflags.StringP("namespace", "n", "", "cluster namespace to use") | ||
viper.BindPFlags(pflags) | ||
|
||
cli.DisableFlagsInUseLine(rootCmd) | ||
} | ||
|
||
// Execute executes the root command. | ||
func Execute() { | ||
if err := rootCmd.Execute(); err != nil { | ||
os.Exit(1) | ||
} | ||
} |
Oops, something went wrong.