initial revision
This commit is contained in:
commit
3fbd407254
1
.gitignore
vendored
Normal file
1
.gitignore
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
bin/*
|
||||||
79
Taskfile.yml
Normal file
79
Taskfile.yml
Normal file
@ -0,0 +1,79 @@
|
|||||||
|
version: '3'
|
||||||
|
|
||||||
|
vars:
|
||||||
|
BINARIES:
|
||||||
|
sh: ls cmd/
|
||||||
|
|
||||||
|
env:
|
||||||
|
GOOS: linux
|
||||||
|
GOARCH: amd64
|
||||||
|
|
||||||
|
tasks:
|
||||||
|
|
||||||
|
default:
|
||||||
|
cmds:
|
||||||
|
- task: build-all
|
||||||
|
|
||||||
|
build-all:
|
||||||
|
desc: build all binaries
|
||||||
|
cmds:
|
||||||
|
- for: { var: BINARIES }
|
||||||
|
task: native-compile-{{.ITEM}}
|
||||||
|
vars:
|
||||||
|
BINARY: '{{.ITEM}}'
|
||||||
|
|
||||||
|
install-all:
|
||||||
|
desc: install all binaries
|
||||||
|
cmds:
|
||||||
|
- for: { var: BINARIES }
|
||||||
|
task: install
|
||||||
|
vars:
|
||||||
|
BINARY: '{{.ITEM}}'
|
||||||
|
|
||||||
|
build-*:
|
||||||
|
desc: build a binary
|
||||||
|
cmd: |
|
||||||
|
mkdir -p bin
|
||||||
|
echo "Building {{.BINARY}} for {{.GOOS}}/{{.GOARCH}}"
|
||||||
|
GOOS={{.GOOS}} GOARCH={{.GOARCH}} go build -o bin/{{.BINARY}}_{{.GOOS}}_{{.GOARCH}} ./cmd/{{.BINARY}}
|
||||||
|
vars:
|
||||||
|
BINARY: '{{index .MATCH 0}}'
|
||||||
|
|
||||||
|
native-compile-*:
|
||||||
|
desc: build a binary
|
||||||
|
cmd: |
|
||||||
|
mkdir -p bin
|
||||||
|
go build -o bin/{{.BINARY}} ./cmd/{{.BINARY}}
|
||||||
|
vars:
|
||||||
|
BINARY: '{{index .MATCH 0}}'
|
||||||
|
|
||||||
|
cross-compile-*:
|
||||||
|
desc: cross compile a binary
|
||||||
|
cmds:
|
||||||
|
- task: build-{{.BINARY}}
|
||||||
|
vars:
|
||||||
|
GOOS: linux
|
||||||
|
GOARCH: amd64
|
||||||
|
- task: build-{{.BINARY}}
|
||||||
|
vars:
|
||||||
|
GOOS: darwin
|
||||||
|
GOARCH: arm64
|
||||||
|
- task: build-{{.BINARY}}
|
||||||
|
vars:
|
||||||
|
GOOS: linux
|
||||||
|
GOARCH: arm64
|
||||||
|
vars:
|
||||||
|
BINARY: '{{index .MATCH 0}}'
|
||||||
|
|
||||||
|
update:
|
||||||
|
desc: update dependencies
|
||||||
|
cmds:
|
||||||
|
- go get -u ./...
|
||||||
|
- go mod tidy
|
||||||
|
|
||||||
|
install:
|
||||||
|
desc: install a binary
|
||||||
|
cmd: |
|
||||||
|
sudo install -m 0755 bin/{{.BINARY}} $DESTDIR/{{.BINARY}}
|
||||||
|
env:
|
||||||
|
DESTDIR: /usr/local/sbin
|
||||||
32
cmd/aws-mgmt/root.go
Normal file
32
cmd/aws-mgmt/root.go
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"log/slog"
|
||||||
|
"os"
|
||||||
|
|
||||||
|
cli "github.com/urfave/cli/v2"
|
||||||
|
|
||||||
|
"aws-mgmt/internal/cmd"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
|
||||||
|
log := slog.New(slog.NewTextHandler(os.Stderr, &slog.HandlerOptions{}))
|
||||||
|
|
||||||
|
// cli.AppHelpTemplate = HelpTemplate
|
||||||
|
|
||||||
|
app := &cli.App{
|
||||||
|
Usage: "AWS management commands",
|
||||||
|
Commands: []*cli.Command{
|
||||||
|
cmd.HibernateCommand,
|
||||||
|
cmd.UpdateACommand,
|
||||||
|
cmd.SecretsCommand,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := app.Run(os.Args); err != nil {
|
||||||
|
log.Error(err.Error())
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
19
cmd/hibernate/root.go
Normal file
19
cmd/hibernate/root.go
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
|
|
||||||
|
"aws-mgmt/internal/cmd"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
|
||||||
|
app := cmd.HibernateApp
|
||||||
|
|
||||||
|
if err := app.Run(os.Args); err != nil {
|
||||||
|
fmt.Fprintln(os.Stderr, err.Error())
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
19
cmd/secrets/root.go
Normal file
19
cmd/secrets/root.go
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
|
|
||||||
|
"aws-mgmt/internal/cmd"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
|
||||||
|
app := cmd.SecretsApp
|
||||||
|
|
||||||
|
if err := app.Run(os.Args); err != nil {
|
||||||
|
fmt.Fprintln(os.Stderr, err.Error())
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
18
cmd/update-a/root.go
Normal file
18
cmd/update-a/root.go
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
|
|
||||||
|
"aws-mgmt/internal/cmd"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
|
||||||
|
app := cmd.UpdateAApp
|
||||||
|
|
||||||
|
if err := app.Run(os.Args); err != nil {
|
||||||
|
fmt.Fprintln(os.Stderr, err.Error())
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
}
|
||||||
115
dist/config.yaml
vendored
Normal file
115
dist/config.yaml
vendored
Normal file
@ -0,0 +1,115 @@
|
|||||||
|
project_name: aws-mgmt-go
|
||||||
|
release:
|
||||||
|
github:
|
||||||
|
owner: jswank
|
||||||
|
name: aws-mgmt-go
|
||||||
|
name_template: '{{.Tag}}'
|
||||||
|
builds:
|
||||||
|
- id: aws-mgmt-go
|
||||||
|
goos:
|
||||||
|
- linux
|
||||||
|
- darwin
|
||||||
|
- windows
|
||||||
|
goarch:
|
||||||
|
- amd64
|
||||||
|
- arm64
|
||||||
|
- "386"
|
||||||
|
goarm:
|
||||||
|
- "6"
|
||||||
|
gomips:
|
||||||
|
- hardfloat
|
||||||
|
goamd64:
|
||||||
|
- v1
|
||||||
|
targets:
|
||||||
|
- linux_amd64_v1
|
||||||
|
- linux_arm64
|
||||||
|
- linux_386
|
||||||
|
- darwin_amd64_v1
|
||||||
|
- darwin_arm64
|
||||||
|
- windows_amd64_v1
|
||||||
|
- windows_arm64
|
||||||
|
- windows_386
|
||||||
|
dir: .
|
||||||
|
main: .
|
||||||
|
binary: aws-mgmt-go
|
||||||
|
builder: go
|
||||||
|
gobinary: go
|
||||||
|
command: build
|
||||||
|
ldflags:
|
||||||
|
- -s -w -X main.version={{.Version}} -X main.commit={{.Commit}} -X main.date={{.Date}} -X main.builtBy=goreleaser
|
||||||
|
archives:
|
||||||
|
- id: default
|
||||||
|
name_template: '{{ .ProjectName }}_{{ .Version }}_{{ .Os }}_{{ .Arch }}{{ with .Arm }}v{{ . }}{{ end }}{{ with .Mips }}_{{ . }}{{ end }}{{ if not (eq .Amd64 "v1") }}{{ .Amd64 }}{{ end }}'
|
||||||
|
format: tar.gz
|
||||||
|
files:
|
||||||
|
- src: license*
|
||||||
|
- src: LICENSE*
|
||||||
|
- src: readme*
|
||||||
|
- src: README*
|
||||||
|
- src: changelog*
|
||||||
|
- src: CHANGELOG*
|
||||||
|
snapshot:
|
||||||
|
name_template: '{{ .Version }}-SNAPSHOT-{{ .ShortCommit }}'
|
||||||
|
checksum:
|
||||||
|
name_template: '{{ .ProjectName }}_{{ .Version }}_checksums.txt'
|
||||||
|
algorithm: sha256
|
||||||
|
changelog:
|
||||||
|
format: '{{ .SHA }}: {{ .Message }} ({{ with .AuthorUsername }}@{{ . }}{{ else }}{{ .AuthorName }} <{{ .AuthorEmail }}>{{ end }})'
|
||||||
|
dist: dist
|
||||||
|
env_files:
|
||||||
|
github_token: ~/.config/goreleaser/github_token
|
||||||
|
gitlab_token: ~/.config/goreleaser/gitlab_token
|
||||||
|
gitea_token: ~/.config/goreleaser/gitea_token
|
||||||
|
source:
|
||||||
|
name_template: '{{ .ProjectName }}-{{ .Version }}'
|
||||||
|
format: tar.gz
|
||||||
|
gomod:
|
||||||
|
gobinary: go
|
||||||
|
announce:
|
||||||
|
twitter:
|
||||||
|
message_template: '{{ .ProjectName }} {{ .Tag }} is out! Check it out at {{ .ReleaseURL }}'
|
||||||
|
mastodon:
|
||||||
|
message_template: '{{ .ProjectName }} {{ .Tag }} is out! Check it out at {{ .ReleaseURL }}'
|
||||||
|
server: ""
|
||||||
|
reddit:
|
||||||
|
title_template: '{{ .ProjectName }} {{ .Tag }} is out!'
|
||||||
|
url_template: '{{ .ReleaseURL }}'
|
||||||
|
slack:
|
||||||
|
message_template: '{{ .ProjectName }} {{ .Tag }} is out! Check it out at {{ .ReleaseURL }}'
|
||||||
|
username: GoReleaser
|
||||||
|
discord:
|
||||||
|
message_template: '{{ .ProjectName }} {{ .Tag }} is out! Check it out at {{ .ReleaseURL }}'
|
||||||
|
author: GoReleaser
|
||||||
|
color: "3888754"
|
||||||
|
icon_url: https://goreleaser.com/static/avatar.png
|
||||||
|
teams:
|
||||||
|
title_template: '{{ .ProjectName }} {{ .Tag }} is out!'
|
||||||
|
message_template: '{{ .ProjectName }} {{ .Tag }} is out! Check it out at {{ .ReleaseURL }}'
|
||||||
|
color: '#2D313E'
|
||||||
|
icon_url: https://goreleaser.com/static/avatar.png
|
||||||
|
smtp:
|
||||||
|
subject_template: '{{ .ProjectName }} {{ .Tag }} is out!'
|
||||||
|
body_template: 'You can view details from: {{ .ReleaseURL }}'
|
||||||
|
mattermost:
|
||||||
|
message_template: '{{ .ProjectName }} {{ .Tag }} is out! Check it out at {{ .ReleaseURL }}'
|
||||||
|
title_template: '{{ .ProjectName }} {{ .Tag }} is out!'
|
||||||
|
username: GoReleaser
|
||||||
|
linkedin:
|
||||||
|
message_template: '{{ .ProjectName }} {{ .Tag }} is out! Check it out at {{ .ReleaseURL }}'
|
||||||
|
telegram:
|
||||||
|
message_template: '{{ mdv2escape .ProjectName }} {{ mdv2escape .Tag }} is out{{ mdv2escape "!" }} Check it out at {{ mdv2escape .ReleaseURL }}'
|
||||||
|
parse_mode: MarkdownV2
|
||||||
|
webhook:
|
||||||
|
message_template: '{ "message": "{{ .ProjectName }} {{ .Tag }} is out! Check it out at {{ .ReleaseURL }}"}'
|
||||||
|
content_type: application/json; charset=utf-8
|
||||||
|
opencollective:
|
||||||
|
title_template: '{{ .Tag }}'
|
||||||
|
message_template: '{{ .ProjectName }} {{ .Tag }} is out!<br/>Check it out at <a href="{{ .ReleaseURL }}">{{ .ReleaseURL }}</a>'
|
||||||
|
bluesky:
|
||||||
|
message_template: '{{ .ProjectName }} {{ .Tag }} is out! Check it out at {{ .ReleaseURL }}'
|
||||||
|
git:
|
||||||
|
tag_sort: -version:refname
|
||||||
|
github_urls:
|
||||||
|
download: https://github.com
|
||||||
|
gitlab_urls:
|
||||||
|
download: https://gitlab.com
|
||||||
1
dist/metadata.json
vendored
Normal file
1
dist/metadata.json
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
{"project_name":"aws-mgmt-go","tag":"v0.0.0","previous_tag":"","version":"0.0.0-SNAPSHOT-a27f612","commit":"a27f6126361f2f72af910005442de0c0701e3df2","date":"2024-11-19T09:03:30.402585616-05:00","runtime":{"goos":"linux","goarch":"amd64"}}
|
||||||
59
go.mod
Normal file
59
go.mod
Normal file
@ -0,0 +1,59 @@
|
|||||||
|
module aws-mgmt
|
||||||
|
|
||||||
|
go 1.21.1
|
||||||
|
|
||||||
|
require (
|
||||||
|
github.com/aws/aws-sdk-go-v2 v1.32.5
|
||||||
|
github.com/aws/aws-sdk-go-v2/config v1.28.5
|
||||||
|
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.20
|
||||||
|
github.com/aws/aws-sdk-go-v2/service/ec2 v1.191.0
|
||||||
|
github.com/aws/aws-sdk-go-v2/service/route53 v1.46.2
|
||||||
|
github.com/aws/aws-sdk-go-v2/service/secretsmanager v1.34.6
|
||||||
|
github.com/charmbracelet/huh v0.6.0
|
||||||
|
github.com/pquerna/otp v1.4.0
|
||||||
|
github.com/urfave/cli/v2 v2.27.5
|
||||||
|
golang.org/x/term v0.26.0
|
||||||
|
)
|
||||||
|
|
||||||
|
require (
|
||||||
|
github.com/atotto/clipboard v0.1.4 // indirect
|
||||||
|
github.com/aws/aws-sdk-go-v2/credentials v1.17.46 // indirect
|
||||||
|
github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.24 // indirect
|
||||||
|
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.24 // indirect
|
||||||
|
github.com/aws/aws-sdk-go-v2/internal/ini v1.8.1 // indirect
|
||||||
|
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.12.1 // indirect
|
||||||
|
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.12.5 // indirect
|
||||||
|
github.com/aws/aws-sdk-go-v2/service/sso v1.24.6 // indirect
|
||||||
|
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.28.5 // indirect
|
||||||
|
github.com/aws/aws-sdk-go-v2/service/sts v1.33.1 // indirect
|
||||||
|
github.com/aws/smithy-go v1.22.1 // indirect
|
||||||
|
github.com/aymanbagabas/go-osc52/v2 v2.0.1 // indirect
|
||||||
|
github.com/boombuler/barcode v1.0.2 // indirect
|
||||||
|
github.com/catppuccin/go v0.2.0 // indirect
|
||||||
|
github.com/charmbracelet/bubbles v0.20.0 // indirect
|
||||||
|
github.com/charmbracelet/bubbletea v1.2.3 // indirect
|
||||||
|
github.com/charmbracelet/lipgloss v1.0.0 // indirect
|
||||||
|
github.com/charmbracelet/x/ansi v0.4.5 // indirect
|
||||||
|
github.com/charmbracelet/x/exp/strings v0.0.0-20241119170951-e919f77bf23b // indirect
|
||||||
|
github.com/charmbracelet/x/term v0.2.1 // indirect
|
||||||
|
github.com/cpuguy83/go-md2man/v2 v2.0.5 // indirect
|
||||||
|
github.com/davecgh/go-spew v1.1.1 // indirect
|
||||||
|
github.com/dustin/go-humanize v1.0.1 // indirect
|
||||||
|
github.com/erikgeiser/coninput v0.0.0-20211004153227-1c3628e74d0f // indirect
|
||||||
|
github.com/jmespath/go-jmespath v0.4.0 // indirect
|
||||||
|
github.com/lucasb-eyer/go-colorful v1.2.0 // indirect
|
||||||
|
github.com/mattn/go-isatty v0.0.20 // indirect
|
||||||
|
github.com/mattn/go-localereader v0.0.1 // indirect
|
||||||
|
github.com/mattn/go-runewidth v0.0.16 // indirect
|
||||||
|
github.com/mitchellh/hashstructure/v2 v2.0.2 // indirect
|
||||||
|
github.com/muesli/ansi v0.0.0-20230316100256-276c6243b2f6 // indirect
|
||||||
|
github.com/muesli/cancelreader v0.2.2 // indirect
|
||||||
|
github.com/muesli/termenv v0.15.3-0.20240618155329-98d742f6907a // indirect
|
||||||
|
github.com/rivo/uniseg v0.4.7 // indirect
|
||||||
|
github.com/russross/blackfriday/v2 v2.1.0 // indirect
|
||||||
|
github.com/xrash/smetrics v0.0.0-20240521201337-686a1a2994c1 // indirect
|
||||||
|
golang.org/x/sync v0.9.0 // indirect
|
||||||
|
golang.org/x/sys v0.27.0 // indirect
|
||||||
|
golang.org/x/text v0.20.0 // indirect
|
||||||
|
gopkg.in/yaml.v2 v2.4.0 // indirect
|
||||||
|
)
|
||||||
116
go.sum
Normal file
116
go.sum
Normal file
@ -0,0 +1,116 @@
|
|||||||
|
github.com/MakeNowJust/heredoc v1.0.0 h1:cXCdzVdstXyiTqTvfqk9SDHpKNjxuom+DOlyEeQ4pzQ=
|
||||||
|
github.com/MakeNowJust/heredoc v1.0.0/go.mod h1:mG5amYoWBHf8vpLOuehzbGGw0EHxpZZ6lCpQ4fNJ8LE=
|
||||||
|
github.com/atotto/clipboard v0.1.4 h1:EH0zSVneZPSuFR11BlR9YppQTVDbh5+16AmcJi4g1z4=
|
||||||
|
github.com/atotto/clipboard v0.1.4/go.mod h1:ZY9tmq7sm5xIbd9bOK4onWV4S6X0u6GY7Vn0Yu86PYI=
|
||||||
|
github.com/aws/aws-sdk-go-v2 v1.32.5 h1:U8vdWJuY7ruAkzaOdD7guwJjD06YSKmnKCJs7s3IkIo=
|
||||||
|
github.com/aws/aws-sdk-go-v2 v1.32.5/go.mod h1:P5WJBrYqqbWVaOxgH0X/FYYD47/nooaPOZPlQdmiN2U=
|
||||||
|
github.com/aws/aws-sdk-go-v2/config v1.28.5 h1:Za41twdCXbuyyWv9LndXxZZv3QhTG1DinqlFsSuvtI0=
|
||||||
|
github.com/aws/aws-sdk-go-v2/config v1.28.5/go.mod h1:4VsPbHP8JdcdUDmbTVgNL/8w9SqOkM5jyY8ljIxLO3o=
|
||||||
|
github.com/aws/aws-sdk-go-v2/credentials v1.17.46 h1:AU7RcriIo2lXjUfHFnFKYsLCwgbz1E7Mm95ieIRDNUg=
|
||||||
|
github.com/aws/aws-sdk-go-v2/credentials v1.17.46/go.mod h1:1FmYyLGL08KQXQ6mcTlifyFXfJVCNJTVGuQP4m0d/UA=
|
||||||
|
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.20 h1:sDSXIrlsFSFJtWKLQS4PUWRvrT580rrnuLydJrCQ/yA=
|
||||||
|
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.20/go.mod h1:WZ/c+w0ofps+/OUqMwWgnfrgzZH1DZO1RIkktICsqnY=
|
||||||
|
github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.24 h1:4usbeaes3yJnCFC7kfeyhkdkPtoRYPa/hTmCqMpKpLI=
|
||||||
|
github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.24/go.mod h1:5CI1JemjVwde8m2WG3cz23qHKPOxbpkq0HaoreEgLIY=
|
||||||
|
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.24 h1:N1zsICrQglfzaBnrfM0Ys00860C+QFwu6u/5+LomP+o=
|
||||||
|
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.24/go.mod h1:dCn9HbJ8+K31i8IQ8EWmWj0EiIk0+vKiHNMxTTYveAg=
|
||||||
|
github.com/aws/aws-sdk-go-v2/internal/ini v1.8.1 h1:VaRN3TlFdd6KxX1x3ILT5ynH6HvKgqdiXoTxAF4HQcQ=
|
||||||
|
github.com/aws/aws-sdk-go-v2/internal/ini v1.8.1/go.mod h1:FbtygfRFze9usAadmnGJNc8KsP346kEe+y2/oyhGAGc=
|
||||||
|
github.com/aws/aws-sdk-go-v2/service/ec2 v1.191.0 h1:F7M5lncJ3dH6VfFohkSTBh0uRmqfB41/XxXfp8NphHI=
|
||||||
|
github.com/aws/aws-sdk-go-v2/service/ec2 v1.191.0/go.mod h1:mzj8EEjIHSN2oZRXiw1Dd+uB4HZTl7hC8nBzX9IZMWw=
|
||||||
|
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.12.1 h1:iXtILhvDxB6kPvEXgsDhGaZCSC6LQET5ZHSdJozeI0Y=
|
||||||
|
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.12.1/go.mod h1:9nu0fVANtYiAePIBh2/pFUSwtJ402hLnp854CNoDOeE=
|
||||||
|
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.12.5 h1:wtpJ4zcwrSbwhECWQoI/g6WM9zqCcSpHDJIWSbMLOu4=
|
||||||
|
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.12.5/go.mod h1:qu/W9HXQbbQ4+1+JcZp0ZNPV31ym537ZJN+fiS7Ti8E=
|
||||||
|
github.com/aws/aws-sdk-go-v2/service/route53 v1.46.2 h1:wmt05tPp/CaRZpPV5B4SaJ5TwkHKom07/BzHoLdkY1o=
|
||||||
|
github.com/aws/aws-sdk-go-v2/service/route53 v1.46.2/go.mod h1:d+K9HESMpGb1EU9/UmmpInbGIUcAkwmcY6ZO/A3zZsw=
|
||||||
|
github.com/aws/aws-sdk-go-v2/service/secretsmanager v1.34.6 h1:1KDMKvOKNrpD667ORbZ/+4OgvUoaok1gg/MLzrHF9fw=
|
||||||
|
github.com/aws/aws-sdk-go-v2/service/secretsmanager v1.34.6/go.mod h1:DmtyfCfONhOyVAJ6ZMTrDSFIeyCBlEO93Qkfhxwbxu0=
|
||||||
|
github.com/aws/aws-sdk-go-v2/service/sso v1.24.6 h1:3zu537oLmsPfDMyjnUS2g+F2vITgy5pB74tHI+JBNoM=
|
||||||
|
github.com/aws/aws-sdk-go-v2/service/sso v1.24.6/go.mod h1:WJSZH2ZvepM6t6jwu4w/Z45Eoi75lPN7DcydSRtJg6Y=
|
||||||
|
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.28.5 h1:K0OQAsDywb0ltlFrZm0JHPY3yZp/S9OaoLU33S7vPS8=
|
||||||
|
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.28.5/go.mod h1:ORITg+fyuMoeiQFiVGoqB3OydVTLkClw/ljbblMq6Cc=
|
||||||
|
github.com/aws/aws-sdk-go-v2/service/sts v1.33.1 h1:6SZUVRQNvExYlMLbHdlKB48x0fLbc2iVROyaNEwBHbU=
|
||||||
|
github.com/aws/aws-sdk-go-v2/service/sts v1.33.1/go.mod h1:GqWyYCwLXnlUB1lOAXQyNSPqPLQJvmo8J0DWBzp9mtg=
|
||||||
|
github.com/aws/smithy-go v1.22.1 h1:/HPHZQ0g7f4eUeK6HKglFz8uwVfZKgoI25rb/J+dnro=
|
||||||
|
github.com/aws/smithy-go v1.22.1/go.mod h1:irrKGvNn1InZwb2d7fkIRNucdfwR8R+Ts3wxYa/cJHg=
|
||||||
|
github.com/aymanbagabas/go-osc52/v2 v2.0.1 h1:HwpRHbFMcZLEVr42D4p7XBqjyuxQH5SMiErDT4WkJ2k=
|
||||||
|
github.com/aymanbagabas/go-osc52/v2 v2.0.1/go.mod h1:uYgXzlJ7ZpABp8OJ+exZzJJhRNQ2ASbcXHWsFqH8hp8=
|
||||||
|
github.com/boombuler/barcode v1.0.1-0.20190219062509-6c824513bacc/go.mod h1:paBWMcWSl3LHKBqUq+rly7CNSldXjb2rDl3JlRe0mD8=
|
||||||
|
github.com/boombuler/barcode v1.0.2 h1:79yrbttoZrLGkL/oOI8hBrUKucwOL0oOjUgEguGMcJ4=
|
||||||
|
github.com/boombuler/barcode v1.0.2/go.mod h1:paBWMcWSl3LHKBqUq+rly7CNSldXjb2rDl3JlRe0mD8=
|
||||||
|
github.com/catppuccin/go v0.2.0 h1:ktBeIrIP42b/8FGiScP9sgrWOss3lw0Z5SktRoithGA=
|
||||||
|
github.com/catppuccin/go v0.2.0/go.mod h1:8IHJuMGaUUjQM82qBrGNBv7LFq6JI3NnQCF6MOlZjpc=
|
||||||
|
github.com/charmbracelet/bubbles v0.20.0 h1:jSZu6qD8cRQ6k9OMfR1WlM+ruM8fkPWkHvQWD9LIutE=
|
||||||
|
github.com/charmbracelet/bubbles v0.20.0/go.mod h1:39slydyswPy+uVOHZ5x/GjwVAFkCsV8IIVy+4MhzwwU=
|
||||||
|
github.com/charmbracelet/bubbletea v1.2.3 h1:d9MdMsANIYZB5pE1KkRqaUV6GfsiWm+/9z4fTuGVm9I=
|
||||||
|
github.com/charmbracelet/bubbletea v1.2.3/go.mod h1:Qr6fVQw+wX7JkWWkVyXYk/ZUQ92a6XNekLXa3rR18MM=
|
||||||
|
github.com/charmbracelet/huh v0.6.0 h1:mZM8VvZGuE0hoDXq6XLxRtgfWyTI3b2jZNKh0xWmax8=
|
||||||
|
github.com/charmbracelet/huh v0.6.0/go.mod h1:GGNKeWCeNzKpEOh/OJD8WBwTQjV3prFAtQPpLv+AVwU=
|
||||||
|
github.com/charmbracelet/lipgloss v1.0.0 h1:O7VkGDvqEdGi93X+DeqsQ7PKHDgtQfF8j8/O2qFMQNg=
|
||||||
|
github.com/charmbracelet/lipgloss v1.0.0/go.mod h1:U5fy9Z+C38obMs+T+tJqst9VGzlOYGj4ri9reL3qUlo=
|
||||||
|
github.com/charmbracelet/x/ansi v0.4.5 h1:LqK4vwBNaXw2AyGIICa5/29Sbdq58GbGdFngSexTdRM=
|
||||||
|
github.com/charmbracelet/x/ansi v0.4.5/go.mod h1:dk73KoMTT5AX5BsX0KrqhsTqAnhZZoCBjs7dGWp4Ktw=
|
||||||
|
github.com/charmbracelet/x/exp/strings v0.0.0-20241119170951-e919f77bf23b h1:zj6aAhsT/hrh2RRuhkrgdwL328Akf26YjSsAArruCNE=
|
||||||
|
github.com/charmbracelet/x/exp/strings v0.0.0-20241119170951-e919f77bf23b/go.mod h1:pBhA0ybfXv6hDjQUZ7hk1lVxBiUbupdw5R31yPUViVQ=
|
||||||
|
github.com/charmbracelet/x/term v0.2.1 h1:AQeHeLZ1OqSXhrAWpYUtZyX1T3zVxfpZuEQMIQaGIAQ=
|
||||||
|
github.com/charmbracelet/x/term v0.2.1/go.mod h1:oQ4enTYFV7QN4m0i9mzHrViD7TQKvNEEkHUMCmsxdUg=
|
||||||
|
github.com/cpuguy83/go-md2man/v2 v2.0.5 h1:ZtcqGrnekaHpVLArFSe4HK5DoKx1T0rq2DwVB0alcyc=
|
||||||
|
github.com/cpuguy83/go-md2man/v2 v2.0.5/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
|
||||||
|
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
|
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||||
|
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
|
github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY=
|
||||||
|
github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto=
|
||||||
|
github.com/erikgeiser/coninput v0.0.0-20211004153227-1c3628e74d0f h1:Y/CXytFA4m6baUTXGLOoWe4PQhGxaX0KpnayAqC48p4=
|
||||||
|
github.com/erikgeiser/coninput v0.0.0-20211004153227-1c3628e74d0f/go.mod h1:vw97MGsxSvLiUE2X8qFplwetxpGLQrlU1Q9AUEIzCaM=
|
||||||
|
github.com/jmespath/go-jmespath v0.4.0 h1:BEgLn5cpjn8UN1mAw4NjwDrS35OdebyEtFe+9YPoQUg=
|
||||||
|
github.com/jmespath/go-jmespath v0.4.0/go.mod h1:T8mJZnbsbmF+m6zOOFylbeCJqk5+pHWvzYPziyZiYoo=
|
||||||
|
github.com/jmespath/go-jmespath/internal/testify v1.5.1 h1:shLQSRRSCCPj3f2gpwzGwWFoC7ycTf1rcQZHOlsJ6N8=
|
||||||
|
github.com/jmespath/go-jmespath/internal/testify v1.5.1/go.mod h1:L3OGu8Wl2/fWfCI6z80xFu9LTZmf1ZRjMHUOPmWr69U=
|
||||||
|
github.com/lucasb-eyer/go-colorful v1.2.0 h1:1nnpGOrhyZZuNyfu1QjKiUICQ74+3FNCN69Aj6K7nkY=
|
||||||
|
github.com/lucasb-eyer/go-colorful v1.2.0/go.mod h1:R4dSotOR9KMtayYi1e77YzuveK+i7ruzyGqttikkLy0=
|
||||||
|
github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
|
||||||
|
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
|
||||||
|
github.com/mattn/go-localereader v0.0.1 h1:ygSAOl7ZXTx4RdPYinUpg6W99U8jWvWi9Ye2JC/oIi4=
|
||||||
|
github.com/mattn/go-localereader v0.0.1/go.mod h1:8fBrzywKY7BI3czFoHkuzRoWE9C+EiG4R1k4Cjx5p88=
|
||||||
|
github.com/mattn/go-runewidth v0.0.16 h1:E5ScNMtiwvlvB5paMFdw9p4kSQzbXFikJ5SQO6TULQc=
|
||||||
|
github.com/mattn/go-runewidth v0.0.16/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=
|
||||||
|
github.com/mitchellh/hashstructure/v2 v2.0.2 h1:vGKWl0YJqUNxE8d+h8f6NJLcCJrgbhC4NcD46KavDd4=
|
||||||
|
github.com/mitchellh/hashstructure/v2 v2.0.2/go.mod h1:MG3aRVU/N29oo/V/IhBX8GR/zz4kQkprJgF2EVszyDE=
|
||||||
|
github.com/muesli/ansi v0.0.0-20230316100256-276c6243b2f6 h1:ZK8zHtRHOkbHy6Mmr5D264iyp3TiX5OmNcI5cIARiQI=
|
||||||
|
github.com/muesli/ansi v0.0.0-20230316100256-276c6243b2f6/go.mod h1:CJlz5H+gyd6CUWT45Oy4q24RdLyn7Md9Vj2/ldJBSIo=
|
||||||
|
github.com/muesli/cancelreader v0.2.2 h1:3I4Kt4BQjOR54NavqnDogx/MIoWBFa0StPA8ELUXHmA=
|
||||||
|
github.com/muesli/cancelreader v0.2.2/go.mod h1:3XuTXfFS2VjM+HTLZY9Ak0l6eUKfijIfMUZ4EgX0QYo=
|
||||||
|
github.com/muesli/termenv v0.15.3-0.20240618155329-98d742f6907a h1:2MaM6YC3mGu54x+RKAA6JiFFHlHDY1UbkxqppT7wYOg=
|
||||||
|
github.com/muesli/termenv v0.15.3-0.20240618155329-98d742f6907a/go.mod h1:hxSnBBYLK21Vtq/PHd0S2FYCxBXzBua8ov5s1RobyRQ=
|
||||||
|
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||||
|
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||||
|
github.com/pquerna/otp v1.4.0 h1:wZvl1TIVxKRThZIBiwOOHOGP/1+nZyWBil9Y2XNEDzg=
|
||||||
|
github.com/pquerna/otp v1.4.0/go.mod h1:dkJfzwRKNiegxyNb54X/3fLwhCynbMspSyWKnvi1AEg=
|
||||||
|
github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
|
||||||
|
github.com/rivo/uniseg v0.4.7 h1:WUdvkW8uEhrYfLC4ZzdpI2ztxP1I582+49Oc5Mq64VQ=
|
||||||
|
github.com/rivo/uniseg v0.4.7/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88=
|
||||||
|
github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk=
|
||||||
|
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
|
||||||
|
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||||
|
github.com/stretchr/testify v1.3.0 h1:TivCn/peBQ7UY8ooIcPgZFpTNSz0Q2U6UrFlUfqbe0Q=
|
||||||
|
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
||||||
|
github.com/urfave/cli/v2 v2.27.5 h1:WoHEJLdsXr6dDWoJgMq/CboDmyY/8HMMH1fTECbih+w=
|
||||||
|
github.com/urfave/cli/v2 v2.27.5/go.mod h1:3Sevf16NykTbInEnD0yKkjDAeZDS0A6bzhBH5hrMvTQ=
|
||||||
|
github.com/xrash/smetrics v0.0.0-20240521201337-686a1a2994c1 h1:gEOO8jv9F4OT7lGCjxCBTO/36wtF6j2nSip77qHd4x4=
|
||||||
|
github.com/xrash/smetrics v0.0.0-20240521201337-686a1a2994c1/go.mod h1:Ohn+xnUBiLI6FVj/9LpzZWtj1/D6lUovWYBkxHVV3aM=
|
||||||
|
golang.org/x/sync v0.9.0 h1:fEo0HyrW1GIgZdpbhCRO0PkJajUS5H9IFUztCgEo2jQ=
|
||||||
|
golang.org/x/sync v0.9.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
|
||||||
|
golang.org/x/sys v0.0.0-20210809222454-d867a43fc93e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
|
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
|
golang.org/x/sys v0.27.0 h1:wBqf8DvsY9Y/2P8gAfPDEYNuS30J4lPHJxXSb/nJZ+s=
|
||||||
|
golang.org/x/sys v0.27.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||||
|
golang.org/x/term v0.26.0 h1:WEQa6V3Gja/BhNxg540hBip/kkaYtRg3cxg4oXSw4AU=
|
||||||
|
golang.org/x/term v0.26.0/go.mod h1:Si5m1o57C5nBNQo5z1iq+XDijt21BDBDp2bK0QI8e3E=
|
||||||
|
golang.org/x/text v0.20.0 h1:gK/Kv2otX8gz+wn7Rmb3vT96ZwuoxnQlY+HlJVj7Qug=
|
||||||
|
golang.org/x/text v0.20.0/go.mod h1:D4IsuqiFMhST5bX19pQ9ikHC2GsaKyk/oF+pn3ducp4=
|
||||||
|
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||||
|
gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||||
|
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
|
||||||
|
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
|
||||||
134
internal/cmd/hibernate.go
Normal file
134
internal/cmd/hibernate.go
Normal file
@ -0,0 +1,134 @@
|
|||||||
|
package cmd
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
cli "github.com/urfave/cli/v2"
|
||||||
|
|
||||||
|
"aws-mgmt/pkg/client"
|
||||||
|
)
|
||||||
|
|
||||||
|
const hibernateDesc = `Hibernate an EC2 instance.
|
||||||
|
|
||||||
|
The TIME string is the number of seconds to delay the hibernation, and defaults
|
||||||
|
to 10. "now" is an alias for 0.
|
||||||
|
|
||||||
|
If run on an EC2 instance with an appropriate IAM EC2 role, the instance will
|
||||||
|
be hibernated. Required IAM permissions include:
|
||||||
|
- ec2:StopInstances
|
||||||
|
|
||||||
|
Alternatively, an instance ID must be specified: that instance will be
|
||||||
|
hibernated. Required IAM permissions include:
|
||||||
|
- ec2:StopInstances
|
||||||
|
`
|
||||||
|
|
||||||
|
var HibernateApp = &cli.App{
|
||||||
|
Name: "hibernate",
|
||||||
|
Usage: "hibernate an instance",
|
||||||
|
UsageText: "hibernate [options] [TIME]",
|
||||||
|
HideHelpCommand: true,
|
||||||
|
Args: true,
|
||||||
|
ArgsUsage: "[TIME]",
|
||||||
|
Action: hibernateFunc,
|
||||||
|
Description: hibernateDesc,
|
||||||
|
Flags: []cli.Flag{
|
||||||
|
&cli.StringFlag{
|
||||||
|
Name: "instance-id",
|
||||||
|
Value: "",
|
||||||
|
Usage: "set the instance id, defaults to the instance running this command",
|
||||||
|
},
|
||||||
|
&cli.StringFlag{
|
||||||
|
Name: "loglevel",
|
||||||
|
Value: "error",
|
||||||
|
Usage: "set the loglevel: debug, info, error",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
var HibernateCommand = &cli.Command{
|
||||||
|
Name: "hibernate",
|
||||||
|
Usage: "hibernate an instance",
|
||||||
|
UsageText: "hibernate [options] [TIME]",
|
||||||
|
HideHelpCommand: true,
|
||||||
|
Args: true,
|
||||||
|
ArgsUsage: "[TIME]",
|
||||||
|
Action: hibernateFunc,
|
||||||
|
Description: hibernateDesc,
|
||||||
|
Flags: []cli.Flag{
|
||||||
|
&cli.StringFlag{
|
||||||
|
Name: "instance-id",
|
||||||
|
Value: "",
|
||||||
|
Usage: "set the instance id, defaults to the instance running this command",
|
||||||
|
},
|
||||||
|
&cli.StringFlag{
|
||||||
|
Name: "loglevel",
|
||||||
|
Value: "error",
|
||||||
|
Usage: "set the loglevel: debug, info, error",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
func hibernateFunc(ctx *cli.Context) error {
|
||||||
|
|
||||||
|
// create logger
|
||||||
|
log, err := createLogger(ctx.String("loglevel"))
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("unable to create a logger, %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// set timer for shutdown
|
||||||
|
timer, err := setTimer(ctx.Args().Get(0))
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
log.Debug("timer is set", "timer", timer)
|
||||||
|
|
||||||
|
// create aws config
|
||||||
|
cfg, err := client.CreateAWSConfig()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
awsClient := client.NewAWSClient(
|
||||||
|
client.SetConfig(cfg),
|
||||||
|
)
|
||||||
|
|
||||||
|
// determine instance id
|
||||||
|
instance_id := ctx.String("instance-id")
|
||||||
|
if instance_id == "" {
|
||||||
|
instance_id, err = awsClient.GetInstanceID()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
log.Debug("instance id is set", "instance_id", instance_id)
|
||||||
|
|
||||||
|
log.Info("waiting to hibernate", "timer", timer)
|
||||||
|
time.Sleep(timer)
|
||||||
|
|
||||||
|
// stop instance
|
||||||
|
state, err := awsClient.StopInstance(instance_id, true)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("unable to stop instance, %w", err)
|
||||||
|
}
|
||||||
|
log.Info("hibernating instance", "instance_id", instance_id, "state", state)
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func setTimer(t string) (time.Duration, error) {
|
||||||
|
var err error
|
||||||
|
timer := time.Duration(10 * time.Second)
|
||||||
|
if t != "" {
|
||||||
|
if t == "now" {
|
||||||
|
timer = time.Duration(0)
|
||||||
|
} else {
|
||||||
|
timer, err = time.ParseDuration(t + "s")
|
||||||
|
if err != nil {
|
||||||
|
return timer, fmt.Errorf("unable to set timer, %w", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return timer, nil
|
||||||
|
}
|
||||||
157
internal/cmd/secrets.go
Normal file
157
internal/cmd/secrets.go
Normal file
@ -0,0 +1,157 @@
|
|||||||
|
package cmd
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
|
"strings"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/charmbracelet/huh"
|
||||||
|
"github.com/pquerna/otp/totp"
|
||||||
|
cli "github.com/urfave/cli/v2"
|
||||||
|
|
||||||
|
"aws-mgmt/pkg/client"
|
||||||
|
)
|
||||||
|
|
||||||
|
const secretsDesc = `View secrets from AWS Secrets Manager.
|
||||||
|
|
||||||
|
`
|
||||||
|
|
||||||
|
var SecretsApp = &cli.App{
|
||||||
|
Name: "secrets",
|
||||||
|
Usage: "view secrets",
|
||||||
|
UsageText: "secrets [options]",
|
||||||
|
HideHelpCommand: true,
|
||||||
|
Args: true,
|
||||||
|
ArgsUsage: "[secret]",
|
||||||
|
Action: secretsFunc,
|
||||||
|
Description: secretsDesc,
|
||||||
|
Flags: []cli.Flag{
|
||||||
|
&cli.BoolFlag{
|
||||||
|
Name: "totp",
|
||||||
|
Usage: "Generate a MFA token based on the secret value",
|
||||||
|
},
|
||||||
|
&cli.StringSliceFlag{
|
||||||
|
Name: "tags",
|
||||||
|
Usage: "Tags in the format key=value",
|
||||||
|
},
|
||||||
|
&cli.BoolFlag{
|
||||||
|
Name: "sh",
|
||||||
|
Usage: "Print the equivalent AWS CLI / shell command(s)",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
var SecretsCommand = &cli.Command{
|
||||||
|
Name: "secrets",
|
||||||
|
Usage: "view secrets",
|
||||||
|
UsageText: "secrets [options]",
|
||||||
|
HideHelpCommand: true,
|
||||||
|
Args: true,
|
||||||
|
ArgsUsage: "[secret]",
|
||||||
|
Action: secretsFunc,
|
||||||
|
Description: secretsDesc,
|
||||||
|
Flags: []cli.Flag{
|
||||||
|
&cli.BoolFlag{
|
||||||
|
Name: "totp",
|
||||||
|
Usage: "Return a MFA token",
|
||||||
|
},
|
||||||
|
&cli.StringSliceFlag{
|
||||||
|
Name: "tags",
|
||||||
|
Usage: "Tags in the format key=value",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
func secretsFunc(c *cli.Context) error {
|
||||||
|
// create aws config
|
||||||
|
cfg, err := client.CreateAWSConfig()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
awsClient := client.NewAWSClient(
|
||||||
|
client.SetConfig(cfg),
|
||||||
|
)
|
||||||
|
|
||||||
|
// get hostname & domain
|
||||||
|
secret := c.Args().Get(0)
|
||||||
|
|
||||||
|
tags := parseTags(c.StringSlice("tags"))
|
||||||
|
|
||||||
|
if secret == "" {
|
||||||
|
secrets, err := awsClient.ListSecrets(tags)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if c.Bool("sh") {
|
||||||
|
str := `aws secretsmanager list-secrets --query 'SecretList[].[Name,Description]' --output text | sort`
|
||||||
|
fmt.Fprintln(os.Stderr, str)
|
||||||
|
}
|
||||||
|
if len(secrets) == 0 {
|
||||||
|
return fmt.Errorf("no secrets found")
|
||||||
|
}
|
||||||
|
secret, err = selectSecretDialog(secrets)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// get secret value for secretName
|
||||||
|
secretValue, err := awsClient.GetSecretValue(secret)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// if the totp flag is set, generate a token
|
||||||
|
if c.Bool("totp") {
|
||||||
|
token, err := totp.GenerateCode(secretValue, time.Now())
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
fmt.Println(token)
|
||||||
|
} else {
|
||||||
|
// print the aws cli equivalent command to output this secret to stderr
|
||||||
|
if c.Bool("sh") {
|
||||||
|
fmt.Fprintln(os.Stderr, fmt.Sprintf("aws secretsmanager get-secret-value --secret-id %s --query SecretString --output text --no-cli-pager",secret))
|
||||||
|
}
|
||||||
|
fmt.Println(secretValue)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
func parseTags(rawTags []string) map[string]string {
|
||||||
|
tags := make(map[string]string)
|
||||||
|
for _, tag := range rawTags {
|
||||||
|
parts := strings.SplitN(tag, "=", 2)
|
||||||
|
if len(parts) == 2 {
|
||||||
|
tags[parts[0]] = parts[1]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return tags
|
||||||
|
}
|
||||||
|
|
||||||
|
// selectSecretDialog prompts the user to select a secret from a list of SecretListEntry
|
||||||
|
func selectSecretDialog(secretList []client.SecretListEntry) (string, error) {
|
||||||
|
|
||||||
|
// create a select prompt for the user to choose a secret
|
||||||
|
var secretName string
|
||||||
|
|
||||||
|
options := make([]huh.Option[string], len(secretList))
|
||||||
|
// options := make([]huh.Option, len(secretList))
|
||||||
|
for i, secret := range secretList {
|
||||||
|
// create a new option for each secret
|
||||||
|
options[i] = huh.NewOption[string](strings.TrimSuffix(fmt.Sprintf("%s: %s", secret.Name, secret.Description), ": "), secret.Name)
|
||||||
|
}
|
||||||
|
|
||||||
|
huh.NewSelect[string]().
|
||||||
|
Title("Select a secret").
|
||||||
|
Options(options...).
|
||||||
|
Value(&secretName).
|
||||||
|
Run()
|
||||||
|
|
||||||
|
return secretName, nil
|
||||||
|
|
||||||
|
}
|
||||||
139
internal/cmd/update-a.go
Normal file
139
internal/cmd/update-a.go
Normal file
@ -0,0 +1,139 @@
|
|||||||
|
package cmd
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
cli "github.com/urfave/cli/v2"
|
||||||
|
|
||||||
|
"aws-mgmt/pkg/client"
|
||||||
|
)
|
||||||
|
|
||||||
|
const updateADesc = `Update a DNS A record for an instance.
|
||||||
|
|
||||||
|
The only required argument is the FQDN: other information required to update
|
||||||
|
the appropriate Route53 record is determined by querying Route53 and IMDS (or
|
||||||
|
EC2) APIs.
|
||||||
|
|
||||||
|
If run on an EC2 instance with an appropriate IAM EC2 role, an A record will be
|
||||||
|
created for that instance. Required IAM permissions include:
|
||||||
|
- route53:ListHostedZonesByName
|
||||||
|
- route53:ChangeResourceRecordSets
|
||||||
|
|
||||||
|
Alternatively, an instance ID must be specified: an A record will be created
|
||||||
|
for that instance. Required IAM permissions include:
|
||||||
|
- route53:ListHostedZonesByName
|
||||||
|
- route53:ChangeResourceRecordSets
|
||||||
|
- ec2:DescribeInstances`
|
||||||
|
|
||||||
|
var UpdateAApp = &cli.App{
|
||||||
|
Name: "update-a",
|
||||||
|
Usage: "Create / update an A record for an instance with a public IP",
|
||||||
|
UsageText: "update-a [options] <FQDN>",
|
||||||
|
HideHelpCommand: true,
|
||||||
|
Args: true,
|
||||||
|
ArgsUsage: "<FQDN>",
|
||||||
|
Action: updateAFunc,
|
||||||
|
Description: updateADesc,
|
||||||
|
Flags: []cli.Flag{
|
||||||
|
&cli.StringFlag{
|
||||||
|
Name: "instance-id",
|
||||||
|
Value: "",
|
||||||
|
Usage: "set the instance id, defaults to the instance running this command",
|
||||||
|
},
|
||||||
|
&cli.StringFlag{
|
||||||
|
Name: "loglevel",
|
||||||
|
Value: "error",
|
||||||
|
Usage: "set the loglevel: debug, info, error",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
var UpdateACommand = &cli.Command{
|
||||||
|
Name: "update-a",
|
||||||
|
Usage: "Create / update an A record for an instance with a public IP",
|
||||||
|
UsageText: "update-a [options] <FQDN>",
|
||||||
|
HideHelpCommand: true,
|
||||||
|
Args: true,
|
||||||
|
ArgsUsage: "<FQDN>",
|
||||||
|
Action: updateAFunc,
|
||||||
|
Description: updateADesc,
|
||||||
|
Flags: []cli.Flag{
|
||||||
|
&cli.StringFlag{
|
||||||
|
Name: "instance-id",
|
||||||
|
Value: "",
|
||||||
|
Usage: "set the instance id, defaults to the instance running this command",
|
||||||
|
},
|
||||||
|
&cli.StringFlag{
|
||||||
|
Name: "loglevel",
|
||||||
|
Value: "error",
|
||||||
|
Usage: "set the loglevel: debug, info, error",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
func updateAFunc(ctx *cli.Context) error {
|
||||||
|
// create logger
|
||||||
|
log, err := createLogger(ctx.String("loglevel"))
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("unable to create a logger, %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// create aws config
|
||||||
|
cfg, err := client.CreateAWSConfig()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
awsClient := client.NewAWSClient(
|
||||||
|
client.SetConfig(cfg),
|
||||||
|
)
|
||||||
|
|
||||||
|
// determine instance id
|
||||||
|
instance_id := ctx.String("instance-id")
|
||||||
|
|
||||||
|
// get hostname & domain
|
||||||
|
hostname := ctx.Args().Get(0)
|
||||||
|
domain, err := parseHostname(hostname)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
log.Debug("input received", "instance-id", instance_id, "hostname", hostname, "domain", domain)
|
||||||
|
|
||||||
|
zoneID, err := awsClient.GetZoneID(domain)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
log.Debug("zone id set", "zone-id", zoneID)
|
||||||
|
|
||||||
|
var publicIP string
|
||||||
|
if instance_id != "" {
|
||||||
|
log.Debug("attempting to retrieve public ip from the EC2 API")
|
||||||
|
publicIP, err = awsClient.GetEC2PublicIP(instance_id)
|
||||||
|
} else {
|
||||||
|
log.Debug("attempting to retrieve public ip from IMDS")
|
||||||
|
publicIP, err = awsClient.GetMetadata("public-ipv4")
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
log.Debug("public ip retrieved", "public_ip", publicIP)
|
||||||
|
|
||||||
|
err = awsClient.UpdateA(hostname, publicIP, zoneID)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
log.Info("dns record updated", "hostname", hostname, "zone-id", zoneID, "public-ipv4", publicIP)
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func parseHostname(h string) (string, error) {
|
||||||
|
var domain string
|
||||||
|
if idx := strings.IndexByte(h, '.'); idx >= 0 {
|
||||||
|
domain = h[idx+1:]
|
||||||
|
} else {
|
||||||
|
return "", fmt.Errorf("hostname (%s) must be a FQDN", h)
|
||||||
|
}
|
||||||
|
return domain, nil
|
||||||
|
}
|
||||||
21
internal/cmd/util.go
Normal file
21
internal/cmd/util.go
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
package cmd
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"log/slog"
|
||||||
|
"os"
|
||||||
|
)
|
||||||
|
|
||||||
|
/* create a logger at the specified loglevel */
|
||||||
|
func createLogger(lvl string) (*slog.Logger, error) {
|
||||||
|
level := slog.LevelError
|
||||||
|
err := level.UnmarshalText([]byte(lvl))
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("invalid log level, %w", err)
|
||||||
|
}
|
||||||
|
log := slog.New(slog.NewTextHandler(os.Stderr, &slog.HandlerOptions{
|
||||||
|
Level: level,
|
||||||
|
}))
|
||||||
|
|
||||||
|
return log, nil
|
||||||
|
}
|
||||||
265
pkg/client/aws.go
Normal file
265
pkg/client/aws.go
Normal file
@ -0,0 +1,265 @@
|
|||||||
|
package client
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"sort"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/aws/aws-sdk-go-v2/aws"
|
||||||
|
"github.com/aws/aws-sdk-go-v2/config"
|
||||||
|
"github.com/aws/aws-sdk-go-v2/feature/ec2/imds"
|
||||||
|
"github.com/aws/aws-sdk-go-v2/service/ec2"
|
||||||
|
"github.com/aws/aws-sdk-go-v2/service/route53"
|
||||||
|
r53 "github.com/aws/aws-sdk-go-v2/service/route53/types"
|
||||||
|
"github.com/aws/aws-sdk-go-v2/service/secretsmanager"
|
||||||
|
sm "github.com/aws/aws-sdk-go-v2/service/secretsmanager/types"
|
||||||
|
)
|
||||||
|
|
||||||
|
type AWSClient struct {
|
||||||
|
cfg aws.Config
|
||||||
|
}
|
||||||
|
|
||||||
|
type SecretListEntry struct {
|
||||||
|
Name string
|
||||||
|
Description string
|
||||||
|
}
|
||||||
|
|
||||||
|
type optionFunc func(*AWSClient)
|
||||||
|
|
||||||
|
func NewAWSClient(optionFuncs ...optionFunc) *AWSClient {
|
||||||
|
awsClient := AWSClient{}
|
||||||
|
for _, option := range optionFuncs {
|
||||||
|
option(&awsClient)
|
||||||
|
}
|
||||||
|
return &awsClient
|
||||||
|
}
|
||||||
|
|
||||||
|
func SetConfig(cfg aws.Config) optionFunc {
|
||||||
|
return func(c *AWSClient) {
|
||||||
|
c.cfg = cfg
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Create config for AWS clients. If region is unset, attempt to set it via IMDS. */
|
||||||
|
func CreateAWSConfig() (aws.Config, error) {
|
||||||
|
cfg, err := config.LoadDefaultConfig(context.TODO())
|
||||||
|
if err != nil {
|
||||||
|
return cfg, fmt.Errorf("unable to load default AWS config, %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// try to set the region using IMDS if it's not already set
|
||||||
|
if cfg.Region == "" {
|
||||||
|
resp, err := imds.NewFromConfig(cfg).GetRegion(context.TODO(), &imds.GetRegionInput{})
|
||||||
|
if err != nil {
|
||||||
|
return cfg, fmt.Errorf("unable to get AWS region from IMDS, %w", err)
|
||||||
|
}
|
||||||
|
cfg, _ = config.LoadDefaultConfig(context.TODO(), config.WithRegion(resp.Region))
|
||||||
|
}
|
||||||
|
return cfg, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Get the running instance id */
|
||||||
|
func (c AWSClient) GetInstanceID() (string, error) {
|
||||||
|
id, err := imds.NewFromConfig(c.cfg).GetInstanceIdentityDocument(context.TODO(), &imds.GetInstanceIdentityDocumentInput{})
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
return id.InstanceID, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// getZoneID returns the zone id given domain
|
||||||
|
func (c AWSClient) GetZoneID(domain string) (string, error) {
|
||||||
|
r53Client := route53.NewFromConfig(c.cfg)
|
||||||
|
output, err := r53Client.ListHostedZonesByName(context.TODO(), &route53.ListHostedZonesByNameInput{
|
||||||
|
DNSName: aws.String(domain),
|
||||||
|
})
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(output.HostedZones) == 0 {
|
||||||
|
return "", errors.New("no matching zone")
|
||||||
|
}
|
||||||
|
|
||||||
|
return *output.HostedZones[0].Id, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetMetadata returns the specified path from instance metadata
|
||||||
|
func (c AWSClient) GetMetadata(path string) (string, error) {
|
||||||
|
imdsClient := imds.NewFromConfig(c.cfg)
|
||||||
|
metadata, err := imdsClient.GetMetadata(context.TODO(), &imds.GetMetadataInput{
|
||||||
|
Path: path,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
buf := new(strings.Builder)
|
||||||
|
_, err = io.Copy(buf, metadata.Content)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
return buf.String(), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c AWSClient) StopInstance(instance_id string, hibernate bool) (string, error) {
|
||||||
|
si_out, err := ec2.NewFromConfig(c.cfg).StopInstances(context.TODO(), &ec2.StopInstancesInput{
|
||||||
|
InstanceIds: []string{instance_id},
|
||||||
|
Hibernate: aws.Bool(hibernate),
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
return string(si_out.StoppingInstances[0].CurrentState.Name), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c AWSClient) GetEC2Tag(instance_id string, tag_name string) (string, error) {
|
||||||
|
result, err := ec2.NewFromConfig(c.cfg).DescribeInstances(context.TODO(), &ec2.DescribeInstancesInput{
|
||||||
|
InstanceIds: []string{instance_id},
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
for _, reservation := range result.Reservations {
|
||||||
|
for _, instance := range reservation.Instances {
|
||||||
|
for _, tag := range instance.Tags {
|
||||||
|
// Check if the tag key matches the one you're interested in
|
||||||
|
if *tag.Key == tag_name {
|
||||||
|
return *tag.Value, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return "", nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c AWSClient) GetEC2PublicIP(instance_id string) (string, error) {
|
||||||
|
var publicIP string
|
||||||
|
result, err := ec2.NewFromConfig(c.cfg).DescribeInstances(context.TODO(), &ec2.DescribeInstancesInput{
|
||||||
|
InstanceIds: []string{instance_id},
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
for _, reservation := range result.Reservations {
|
||||||
|
for _, instance := range reservation.Instances {
|
||||||
|
if instance.PublicIpAddress != nil {
|
||||||
|
publicIP = *instance.PublicIpAddress
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if publicIP == "" {
|
||||||
|
err = errors.New("no public ip address is associated with the instance")
|
||||||
|
}
|
||||||
|
return publicIP, err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c AWSClient) UpdateA(hostname, ipaddress, zoneID string) error {
|
||||||
|
|
||||||
|
change := r53.Change{
|
||||||
|
Action: "UPSERT",
|
||||||
|
ResourceRecordSet: &r53.ResourceRecordSet{
|
||||||
|
Name: aws.String(hostname),
|
||||||
|
Type: "A",
|
||||||
|
TTL: aws.Int64(60),
|
||||||
|
ResourceRecords: []r53.ResourceRecord{
|
||||||
|
r53.ResourceRecord{Value: aws.String(ipaddress)},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err := route53.NewFromConfig(c.cfg).ChangeResourceRecordSets(context.TODO(), &route53.ChangeResourceRecordSetsInput{
|
||||||
|
HostedZoneId: aws.String(zoneID),
|
||||||
|
ChangeBatch: &r53.ChangeBatch{
|
||||||
|
Changes: []r53.Change{change},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
return err
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// ListSecrets lists all secrets with tags matching the tags map, returning a sorted list
|
||||||
|
// of secrets names and descriptions from the response.
|
||||||
|
func (c AWSClient) ListSecrets(tags map[string]string) ([]SecretListEntry, error) {
|
||||||
|
client := secretsmanager.NewFromConfig(c.cfg)
|
||||||
|
|
||||||
|
// construct filters from tags map
|
||||||
|
var filters []sm.Filter
|
||||||
|
// filters := make([]sm.Filter, 0, len(tags)*2)
|
||||||
|
for key, value := range tags {
|
||||||
|
filters = append(filters, sm.Filter{
|
||||||
|
Key: sm.FilterNameStringTypeTagKey,
|
||||||
|
Values: []string{key},
|
||||||
|
})
|
||||||
|
if value != "" {
|
||||||
|
filters = append(filters, sm.Filter{
|
||||||
|
Key: sm.FilterNameStringTypeTagValue,
|
||||||
|
Values: []string{value},
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var secretList []SecretListEntry
|
||||||
|
|
||||||
|
// Set the initial pagination token to an empty string
|
||||||
|
var nextToken *string
|
||||||
|
|
||||||
|
// Loop until there are no more pages
|
||||||
|
for {
|
||||||
|
// Call ListSecrets with the pagination token
|
||||||
|
input := &secretsmanager.ListSecretsInput{
|
||||||
|
Filters: filters,
|
||||||
|
NextToken: nextToken,
|
||||||
|
}
|
||||||
|
resp, err := client.ListSecrets(context.TODO(), input)
|
||||||
|
if err != nil {
|
||||||
|
return secretList, fmt.Errorf("unable to list secrets, %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Process the secrets in the current page
|
||||||
|
for _, secret := range resp.SecretList {
|
||||||
|
entry := SecretListEntry{
|
||||||
|
Name: *secret.Name,
|
||||||
|
}
|
||||||
|
if secret.Description != nil {
|
||||||
|
entry.Description = *secret.Description
|
||||||
|
}
|
||||||
|
secretList = append(secretList, entry)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if there are more pages
|
||||||
|
if resp.NextToken == nil {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
// Set the pagination token for the next iteration
|
||||||
|
nextToken = resp.NextToken
|
||||||
|
}
|
||||||
|
|
||||||
|
// sort secretList alphabetically by name
|
||||||
|
sort.Slice(secretList, func(i, j int) bool {
|
||||||
|
return secretList[i].Name < secretList[j].Name
|
||||||
|
})
|
||||||
|
|
||||||
|
return secretList, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetSecretValue retrieves the secret value for the given secret name.
|
||||||
|
func (c AWSClient) GetSecretValue(secretName string) (string, error) {
|
||||||
|
client := secretsmanager.NewFromConfig(c.cfg)
|
||||||
|
|
||||||
|
input := &secretsmanager.GetSecretValueInput{
|
||||||
|
SecretId: &secretName,
|
||||||
|
}
|
||||||
|
|
||||||
|
resp, err := client.GetSecretValue(context.TODO(), input)
|
||||||
|
if err != nil {
|
||||||
|
return "", fmt.Errorf("unable to get secret value, %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return *resp.SecretString, nil
|
||||||
|
}
|
||||||
15
pkg/logout/now.go
Normal file
15
pkg/logout/now.go
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
package logout
|
||||||
|
|
||||||
|
import (
|
||||||
|
"os"
|
||||||
|
"syscall"
|
||||||
|
|
||||||
|
"golang.org/x/term"
|
||||||
|
)
|
||||||
|
|
||||||
|
func Now() {
|
||||||
|
if term.IsTerminal(int(os.Stdout.Fd())) {
|
||||||
|
ppid := os.Getppid()
|
||||||
|
_ = syscall.Kill(ppid, 1)
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue
Block a user