Report queued tasks the scheduling pass never considers
A task in retry backoff was filtered out before the candidate loop, so it recorded no rejection at all: queued, apparently assignable, and silent. That is the exact shape that made F5 take a live session to diagnose. It now reports "retry backoff until <time>". Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,91 @@
|
||||
// orchestra-user manages browser-operator accounts in Orchestra's embedded
|
||||
// credential database. Passwords are read from the terminal and hashed inside
|
||||
// the database; no reusable hash has to be copied into deployment config.
|
||||
package main
|
||||
|
||||
import (
|
||||
"flag"
|
||||
"fmt"
|
||||
"log"
|
||||
"orchestra/internal/authn"
|
||||
"os"
|
||||
"syscall"
|
||||
|
||||
"golang.org/x/term"
|
||||
)
|
||||
|
||||
func usage() {
|
||||
fmt.Fprintln(os.Stderr, "usage:")
|
||||
fmt.Fprintln(os.Stderr, " orchestra-user set -data DIR -username NAME")
|
||||
fmt.Fprintln(os.Stderr, " orchestra-user list -data DIR")
|
||||
}
|
||||
|
||||
func readPassword(prompt string) (string, error) {
|
||||
fmt.Fprint(os.Stderr, prompt)
|
||||
value, err := term.ReadPassword(int(syscall.Stdin))
|
||||
fmt.Fprintln(os.Stderr)
|
||||
return string(value), err
|
||||
}
|
||||
|
||||
func open(data string) *authn.Store {
|
||||
if data == "" {
|
||||
log.Fatal("-data is required")
|
||||
}
|
||||
users, err := authn.Open(authn.Path(data))
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
return users
|
||||
}
|
||||
|
||||
func main() {
|
||||
if len(os.Args) < 2 {
|
||||
usage()
|
||||
os.Exit(2)
|
||||
}
|
||||
switch os.Args[1] {
|
||||
case "set":
|
||||
flags := flag.NewFlagSet("set", flag.ExitOnError)
|
||||
data := flags.String("data", "", "Orchestra data directory")
|
||||
username := flags.String("username", "", "operator username")
|
||||
_ = flags.Parse(os.Args[2:])
|
||||
password, err := readPassword("New password: ")
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
confirmation, err := readPassword("Confirm password: ")
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
if password != confirmation {
|
||||
log.Fatal("passwords do not match")
|
||||
}
|
||||
users := open(*data)
|
||||
defer users.Close()
|
||||
user, created, err := users.SetPassword(*username, password)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
if created {
|
||||
fmt.Printf("created operator %s\n", user.Username)
|
||||
} else {
|
||||
fmt.Printf("updated password for %s\n", user.Username)
|
||||
}
|
||||
case "list":
|
||||
flags := flag.NewFlagSet("list", flag.ExitOnError)
|
||||
data := flags.String("data", "", "Orchestra data directory")
|
||||
_ = flags.Parse(os.Args[2:])
|
||||
users := open(*data)
|
||||
defer users.Close()
|
||||
list, err := users.Users()
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
for _, user := range list {
|
||||
fmt.Println(user.Username)
|
||||
}
|
||||
default:
|
||||
usage()
|
||||
os.Exit(2)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user