Adds ecs and fixes wez for remote hosts
This commit is contained in:
@@ -0,0 +1,146 @@
|
|||||||
|
#!/usr/bin/env nu
|
||||||
|
# Inspect an ECS service: show task status, or fetch recent CloudWatch logs.
|
||||||
|
# Requires: AWS CLI v2, configured credentials, and permissions for ECS/CloudWatch Logs.
|
||||||
|
#
|
||||||
|
# Examples:
|
||||||
|
# ecs tasks my-cluster my-service
|
||||||
|
# ecs logs my-cluster my-service --tail 100
|
||||||
|
# ecs logs my-cluster my-service --region us-east-1
|
||||||
|
|
||||||
|
const default_tail = 50
|
||||||
|
|
||||||
|
def main [
|
||||||
|
mode: string # `tasks` or `logs`
|
||||||
|
cluster: string # ECS cluster name or ARN
|
||||||
|
service: string # ECS service name or ARN
|
||||||
|
--tail: int = $default_tail # Number of recent log events to show
|
||||||
|
--region: string # AWS region; otherwise AWS CLI configuration is used
|
||||||
|
] {
|
||||||
|
if $mode not-in [tasks logs] {
|
||||||
|
error make {msg: $"mode must be `tasks` or `logs`; got `($mode)`"}
|
||||||
|
}
|
||||||
|
|
||||||
|
let aws_args = if ($region | is-empty) { [] } else { [--region $region] }
|
||||||
|
let task_arns = (
|
||||||
|
^aws ...$aws_args ecs list-tasks
|
||||||
|
--cluster $cluster
|
||||||
|
--service-name $service
|
||||||
|
--desired-status RUNNING
|
||||||
|
--query 'taskArns'
|
||||||
|
--output json
|
||||||
|
| from json
|
||||||
|
)
|
||||||
|
|
||||||
|
if ($task_arns | is-empty) {
|
||||||
|
print $"No RUNNING tasks found for service `($service)` in cluster `($cluster)`."
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if $mode == tasks {
|
||||||
|
(
|
||||||
|
^aws ...$aws_args ecs describe-tasks
|
||||||
|
--cluster $cluster
|
||||||
|
--tasks ...$task_arns
|
||||||
|
--query 'tasks[].{taskArn:taskArn,lastStatus:lastStatus,desiredStatus:desiredStatus,healthStatus:healthStatus,startedAt:startedAt,stoppedReason:stoppedReason,containers:containers[].{name:name,lastStatus:lastStatus,exitCode:exitCode,reason:reason}}'
|
||||||
|
--output json
|
||||||
|
| from json
|
||||||
|
| table -e
|
||||||
|
| print
|
||||||
|
)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
let definition_arn = (
|
||||||
|
^aws ...$aws_args ecs describe-tasks
|
||||||
|
--cluster $cluster
|
||||||
|
--tasks ($task_arns | first)
|
||||||
|
--query 'tasks[0].taskDefinitionArn'
|
||||||
|
--output text
|
||||||
|
| str trim
|
||||||
|
)
|
||||||
|
|
||||||
|
let container_definitions = (
|
||||||
|
^aws ...$aws_args ecs describe-task-definition
|
||||||
|
--task-definition $definition_arn
|
||||||
|
--query 'taskDefinition.containerDefinitions[].{name:name,logDriver:logConfiguration.logDriver,options:logConfiguration.options}'
|
||||||
|
--output json
|
||||||
|
| from json
|
||||||
|
)
|
||||||
|
|
||||||
|
let awslogs = ($container_definitions | where logDriver == 'awslogs')
|
||||||
|
if ($awslogs | is-empty) {
|
||||||
|
error make {msg: $"Task definition `($definition_arn)` has no containers using the awslogs log driver."}
|
||||||
|
}
|
||||||
|
|
||||||
|
for container in $awslogs {
|
||||||
|
let group = ($container.options | get 'awslogs-group')
|
||||||
|
let prefix = ($container.options | get 'awslogs-stream-prefix')
|
||||||
|
let stream_prefix = $"($prefix)/($container.name)/"
|
||||||
|
|
||||||
|
# get-log-events returns a stream's most recent events by default, so walk
|
||||||
|
# streams newest-first and stop once no remaining stream can hold an event
|
||||||
|
# newer than the ones collected. (describe-log-streams can't combine a
|
||||||
|
# stream prefix with LastEventTime ordering, so filter by prefix here.)
|
||||||
|
print $"\n==> CloudWatch log group: ($group), stream prefix: ($stream_prefix)"
|
||||||
|
let limit = ([$tail 10000] | math min)
|
||||||
|
mut events = []
|
||||||
|
mut next_token = ''
|
||||||
|
mut done = false
|
||||||
|
loop {
|
||||||
|
let token_args = if ($next_token | is-empty) { [] } else { [--next-token $next_token] }
|
||||||
|
let page = (
|
||||||
|
^aws ...$aws_args logs describe-log-streams
|
||||||
|
--log-group-name $group
|
||||||
|
--order-by LastEventTime
|
||||||
|
--descending
|
||||||
|
--limit 50
|
||||||
|
--output json
|
||||||
|
...$token_args
|
||||||
|
| from json
|
||||||
|
)
|
||||||
|
# project the fields we need and keep the page's nextToken
|
||||||
|
let streams = (
|
||||||
|
$page.logStreams?
|
||||||
|
| default []
|
||||||
|
| each {|s| {name: $s.logStreamName, last: ($s.lastEventTimestamp? | default null)}}
|
||||||
|
| where name starts-with $stream_prefix
|
||||||
|
)
|
||||||
|
let next = ($page.nextToken? | default '')
|
||||||
|
for stream in $streams {
|
||||||
|
let last = ($stream.last? | default null)
|
||||||
|
let have_enough = ($events | length) >= $tail
|
||||||
|
let oldest = (if ($events | is-empty) { null } else { $events | get timestamp | math min })
|
||||||
|
# skip empty streams; stop when this stream's newest event is older
|
||||||
|
# than what we already have (later streams are even older)
|
||||||
|
if $last == null or ($have_enough and $last < $oldest) {
|
||||||
|
if $last != null {
|
||||||
|
$done = true
|
||||||
|
break
|
||||||
|
}
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
let recent = (
|
||||||
|
^aws ...$aws_args logs get-log-events
|
||||||
|
--log-group-name $group
|
||||||
|
--log-stream-name $stream.name
|
||||||
|
--limit $limit
|
||||||
|
--query 'events[].{timestamp:timestamp,message:message}'
|
||||||
|
--output json
|
||||||
|
| from json
|
||||||
|
| each {|e| {timestamp: $e.timestamp, message: $e.message, stream: $stream.name}}
|
||||||
|
)
|
||||||
|
$events = ($events | append $recent | sort-by timestamp | last $tail)
|
||||||
|
}
|
||||||
|
if $done or ($next | is-empty) {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
$next_token = $next
|
||||||
|
}
|
||||||
|
|
||||||
|
for event in $events {
|
||||||
|
let time = (($event.timestamp | into int) * 1000000 | into datetime | format date '%Y-%m-%dT%H:%M:%S%.3f%:z')
|
||||||
|
let task_id = ($event.stream | split row '/' | last)
|
||||||
|
print $"($time) ($task_id) ($event.message)"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -4,11 +4,18 @@ $env.SSH_AUTH_SOCK = ""
|
|||||||
$env.SSH_ASKPASS = "/usr/bin/ksshaskpass"
|
$env.SSH_ASKPASS = "/usr/bin/ksshaskpass"
|
||||||
$env.SSH_ASKPASS_REQUIRE = "force"
|
$env.SSH_ASKPASS_REQUIRE = "force"
|
||||||
|
|
||||||
def main [--domain: string, --theme: string = "Ef-Dream", --font: string = "LythMono Nerd Font", --font_size: int = 12] {
|
def main [ --domain: string
|
||||||
|
, --theme: string = "Ef-Dream"
|
||||||
|
, --font: string = "LythMono Nerd Font"
|
||||||
|
, --font_size: int = 12
|
||||||
|
, --remote = false
|
||||||
|
] {
|
||||||
let color_scheme = "color_scheme='" + $theme + "'"
|
let color_scheme = "color_scheme='" + $theme + "'"
|
||||||
let wez_font = 'font=wezterm.font("' + $font + '")'
|
let wez_font = 'font=wezterm.font("' + $font + '")'
|
||||||
let wez_font_size = 'font_size=' + ($font_size | into string)
|
let wez_font_size = 'font_size=' + ($font_size | into string)
|
||||||
|
if (not $remote) {
|
||||||
$env.WEZTERM_MUX_SOCKET_NAME = $domain
|
$env.WEZTERM_MUX_SOCKET_NAME = $domain
|
||||||
|
}
|
||||||
|
|
||||||
(
|
(
|
||||||
wezterm
|
wezterm
|
||||||
|
|||||||
@@ -68,28 +68,34 @@
|
|||||||
, exec: "/usr/bin/obsidian"
|
, exec: "/usr/bin/obsidian"
|
||||||
, args: []
|
, args: []
|
||||||
}
|
}
|
||||||
, { name: "WezTerm (Local)"
|
, { name: "WezTerm (Local - Host)"
|
||||||
, app_id: "lol.roo.term.local-unix"
|
, app_id: "lol.roo.term.local-unix"
|
||||||
, exec: "/home/jbrechtel/bin/wez"
|
, exec: "/home/jbrechtel/bin/wez"
|
||||||
, args: ["--domain", "local-unix", "--theme", "Ef-Dream", "--font", "Hurmit Nerd Font Mono"]
|
, args: ["--domain", "local-unix", "--theme", "Ef-Dream", "--font", "Hurmit Nerd Font Mono"]
|
||||||
, tags: ["terminals"]
|
, tags: ["terminals"]
|
||||||
}
|
}
|
||||||
|
, { name: "WezTerm (Local - Agent)"
|
||||||
|
, app_id: "lol.roo.term.local-agent-unix"
|
||||||
|
, exec: "/home/jbrechtel/bin/wez"
|
||||||
|
, args: ["--domain", "local-agent-unix", "--theme", "Ef-Dream", "--font", "IosevkaTerm Nerd Font Mono", "--remote", "true"]
|
||||||
|
, tags: ["terminals"]
|
||||||
|
}
|
||||||
, { name: "WezTerm (pandemic.brechtel)"
|
, { name: "WezTerm (pandemic.brechtel)"
|
||||||
, app_id: "lol.roo.term.pandemic.brechtel"
|
, app_id: "lol.roo.term.pandemic.brechtel"
|
||||||
, exec: "/home/jbrechtel/bin/wez"
|
, exec: "/home/jbrechtel/bin/wez"
|
||||||
, args: ["--domain", "pandemic.brechtel", "--theme", "Ef-Night", "--font", "ZedMono Nerd Font Mono"]
|
, args: ["--domain", "pandemic.brechtel", "--theme", "Ef-Night", "--font", "ZedMono Nerd Font Mono", "--remote", "true"]
|
||||||
, tags: ["terminals"]
|
, tags: ["terminals"]
|
||||||
}
|
}
|
||||||
, { name: "WezTerm (Flipstone - Host)"
|
, { name: "WezTerm (Flipstone - Host)"
|
||||||
, app_id: "lol.roo.term.local-flipstone-unix"
|
, app_id: "lol.roo.term.local-flipstone-unix"
|
||||||
, exec: "/home/jbrechtel/bin/wez"
|
, exec: "/home/jbrechtel/bin/wez"
|
||||||
, args: ["--domain", "local-flipstone-unix", "--theme", "Ef-Maris-Dark", "--font", "Agave Nerd Font Mono"]
|
, args: ["--domain", "local-flipstone-unix", "--theme", "Ef-Maris-Dark", "--font", "AurulentSansM Nerd Font Mono", "--font_size", "11"]
|
||||||
, tags: ["terminals"]
|
, tags: ["terminals"]
|
||||||
}
|
}
|
||||||
, { name: "WezTerm (Flipstone - Agent)"
|
, { name: "WezTerm (Flipstone - Agent)"
|
||||||
, app_id: "lol.roo.home.term.flipstone-dev"
|
, app_id: "lol.roo.term.local-flipstone-agent-unix"
|
||||||
, exec: "/home/jbrechtel/bin/wez"
|
, exec: "/home/jbrechtel/bin/wez"
|
||||||
, args: ["--domain", "flipstone-dev", "--theme", "Ef-Bio", "--font", "IosevkaTermSlab Nerd Font"]
|
, args: ["--domain", "local-flipstone-agent-unix", "--theme", "Ef-Bio", "--font", "IosevkaTermSlab Nerd Font", "--remote", "true"]
|
||||||
, tags: ["terminals"]
|
, tags: ["terminals"]
|
||||||
}
|
}
|
||||||
, { name: "WezTerm-Flipstone-FSDB"
|
, { name: "WezTerm-Flipstone-FSDB"
|
||||||
|
|||||||
Reference in New Issue
Block a user