forked from coop-cloud/abra
Compare commits
2 Commits
Author | SHA1 | Date |
---|---|---|
knoflook | ed859c0243 | |
knoflook | 236d0f5892 |
|
@ -4,74 +4,54 @@ import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"os"
|
"os"
|
||||||
"sync"
|
|
||||||
|
|
||||||
"coopcloud.tech/abra/cli/internal"
|
"coopcloud.tech/abra/cli/internal"
|
||||||
"coopcloud.tech/abra/pkg/client"
|
"coopcloud.tech/abra/pkg/client"
|
||||||
"coopcloud.tech/abra/pkg/config"
|
"coopcloud.tech/abra/pkg/config"
|
||||||
"github.com/docker/docker/api/types"
|
"github.com/docker/docker/api/types"
|
||||||
"github.com/docker/docker/api/types/filters"
|
"github.com/docker/docker/api/types/filters"
|
||||||
dockerClient "github.com/docker/docker/client"
|
|
||||||
"github.com/sirupsen/logrus"
|
"github.com/sirupsen/logrus"
|
||||||
"github.com/urfave/cli/v2"
|
"github.com/urfave/cli/v2"
|
||||||
)
|
)
|
||||||
|
|
||||||
// stackLogs lists logs for all stack services
|
|
||||||
func stackLogs(c *cli.Context, stackName string, client *dockerClient.Client) {
|
|
||||||
filters := filters.NewArgs()
|
|
||||||
filters.Add("name", stackName)
|
|
||||||
serviceOpts := types.ServiceListOptions{Filters: filters}
|
|
||||||
services, err := client.ServiceList(c.Context, serviceOpts)
|
|
||||||
if err != nil {
|
|
||||||
logrus.Fatal(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
var wg sync.WaitGroup
|
|
||||||
for _, service := range services {
|
|
||||||
wg.Add(1)
|
|
||||||
go func(s string) {
|
|
||||||
logOpts := types.ContainerLogsOptions{
|
|
||||||
Details: false,
|
|
||||||
Follow: true,
|
|
||||||
ShowStderr: true,
|
|
||||||
ShowStdout: true,
|
|
||||||
Tail: "20",
|
|
||||||
Timestamps: true,
|
|
||||||
}
|
|
||||||
logs, err := client.ServiceLogs(c.Context, s, logOpts)
|
|
||||||
if err != nil {
|
|
||||||
logrus.Fatal(err)
|
|
||||||
}
|
|
||||||
// defer after err check as any err returns a nil io.ReadCloser
|
|
||||||
defer logs.Close()
|
|
||||||
|
|
||||||
_, err = io.Copy(os.Stdout, logs)
|
|
||||||
if err != nil && err != io.EOF {
|
|
||||||
logrus.Fatal(err)
|
|
||||||
}
|
|
||||||
}(service.ID)
|
|
||||||
}
|
|
||||||
wg.Wait()
|
|
||||||
os.Exit(0)
|
|
||||||
}
|
|
||||||
|
|
||||||
var appLogsCommand = &cli.Command{
|
var appLogsCommand = &cli.Command{
|
||||||
Name: "logs",
|
Name: "logs",
|
||||||
Aliases: []string{"l"},
|
Aliases: []string{"l"},
|
||||||
ArgsUsage: "[<service>]",
|
ArgsUsage: "[<service>]",
|
||||||
Usage: "Tail app logs",
|
Usage: "Tail app logs",
|
||||||
|
Flags: []cli.Flag{
|
||||||
|
internal.StderrFlag,
|
||||||
|
internal.StdoutFlag,
|
||||||
|
internal.HealthcheckFlag,
|
||||||
|
},
|
||||||
Action: func(c *cli.Context) error {
|
Action: func(c *cli.Context) error {
|
||||||
app := internal.ValidateApp(c)
|
app := internal.ValidateApp(c)
|
||||||
|
|
||||||
|
if !internal.Stderr && !internal.Stdout && !internal.Healthcheck {
|
||||||
|
internal.Stderr = true
|
||||||
|
internal.Stdout = true
|
||||||
|
internal.Healthcheck = true
|
||||||
|
}
|
||||||
|
|
||||||
|
logrus.Debugf("flags parsed. --stderr: %t, --stdout: %t, --healthcheck: %t", internal.Stderr, internal.Stdout, internal.Healthcheck)
|
||||||
cl, err := client.New(app.Server)
|
cl, err := client.New(app.Server)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logrus.Fatal(err)
|
logrus.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
logOpts := types.ContainerLogsOptions{
|
||||||
|
Details: false,
|
||||||
|
Follow: true,
|
||||||
|
ShowStderr: internal.Stderr,
|
||||||
|
ShowStdout: internal.Stdout,
|
||||||
|
Tail: "20",
|
||||||
|
Timestamps: true,
|
||||||
|
}
|
||||||
|
|
||||||
serviceName := c.Args().Get(1)
|
serviceName := c.Args().Get(1)
|
||||||
if serviceName == "" {
|
if serviceName == "" {
|
||||||
logrus.Debug("tailing logs for all app services")
|
logrus.Debug("tailing logs for all app services")
|
||||||
stackLogs(c, app.StackName(), cl)
|
internal.StackLogs(c, app.StackName(), logOpts, cl)
|
||||||
}
|
}
|
||||||
logrus.Debugf("tailing logs for '%s'", serviceName)
|
logrus.Debugf("tailing logs for '%s'", serviceName)
|
||||||
|
|
||||||
|
@ -87,14 +67,6 @@ var appLogsCommand = &cli.Command{
|
||||||
logrus.Fatalf("expected 1 service but got %v", len(services))
|
logrus.Fatalf("expected 1 service but got %v", len(services))
|
||||||
}
|
}
|
||||||
|
|
||||||
logOpts := types.ContainerLogsOptions{
|
|
||||||
Details: false,
|
|
||||||
Follow: true,
|
|
||||||
ShowStderr: true,
|
|
||||||
ShowStdout: true,
|
|
||||||
Tail: "20",
|
|
||||||
Timestamps: true,
|
|
||||||
}
|
|
||||||
logs, err := cl.ServiceLogs(c.Context, services[0].ID, logOpts)
|
logs, err := cl.ServiceLogs(c.Context, services[0].ID, logOpts)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logrus.Fatal(err)
|
logrus.Fatal(err)
|
||||||
|
|
|
@ -0,0 +1,68 @@
|
||||||
|
package internal
|
||||||
|
|
||||||
|
import (
|
||||||
|
"io"
|
||||||
|
"os"
|
||||||
|
"sync"
|
||||||
|
|
||||||
|
"github.com/docker/docker/api/types"
|
||||||
|
"github.com/docker/docker/api/types/filters"
|
||||||
|
dockerClient "github.com/docker/docker/client"
|
||||||
|
"github.com/sirupsen/logrus"
|
||||||
|
"github.com/urfave/cli/v2"
|
||||||
|
)
|
||||||
|
|
||||||
|
var Stderr bool
|
||||||
|
var StderrFlag = &cli.BoolFlag{
|
||||||
|
Name: "stderr",
|
||||||
|
Aliases: []string{"e"},
|
||||||
|
Value: false,
|
||||||
|
Destination: &Stderr,
|
||||||
|
}
|
||||||
|
|
||||||
|
var Stdout bool
|
||||||
|
var StdoutFlag = &cli.BoolFlag{
|
||||||
|
Name: "stdout",
|
||||||
|
Aliases: []string{"o"},
|
||||||
|
Value: false,
|
||||||
|
Destination: &Stdout,
|
||||||
|
}
|
||||||
|
|
||||||
|
var Healthcheck bool
|
||||||
|
var HealthcheckFlag = &cli.BoolFlag{
|
||||||
|
Name: "healthcheck",
|
||||||
|
Aliases: []string{"c"},
|
||||||
|
Value: false,
|
||||||
|
Destination: &Healthcheck,
|
||||||
|
}
|
||||||
|
|
||||||
|
// StackLogs lists logs for all stack services
|
||||||
|
func StackLogs(c *cli.Context, stackName string, logOpts types.ContainerLogsOptions, client *dockerClient.Client) {
|
||||||
|
filters := filters.NewArgs()
|
||||||
|
filters.Add("name", stackName)
|
||||||
|
serviceOpts := types.ServiceListOptions{Filters: filters}
|
||||||
|
services, err := client.ServiceList(c.Context, serviceOpts)
|
||||||
|
if err != nil {
|
||||||
|
logrus.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
var wg sync.WaitGroup
|
||||||
|
for _, service := range services {
|
||||||
|
wg.Add(1)
|
||||||
|
go func(s string) {
|
||||||
|
logs, err := client.ServiceLogs(c.Context, s, logOpts)
|
||||||
|
if err != nil {
|
||||||
|
logrus.Fatal(err)
|
||||||
|
}
|
||||||
|
// defer after err check as any err returns a nil io.ReadCloser
|
||||||
|
defer logs.Close()
|
||||||
|
|
||||||
|
_, err = io.Copy(os.Stdout, logs)
|
||||||
|
if err != nil && err != io.EOF {
|
||||||
|
logrus.Fatal(err)
|
||||||
|
}
|
||||||
|
}(service.ID)
|
||||||
|
}
|
||||||
|
wg.Wait()
|
||||||
|
os.Exit(0)
|
||||||
|
}
|
|
@ -112,6 +112,35 @@ func ValidateApp(c *cli.Context) config.App {
|
||||||
return app
|
return app
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ValidateAppByName ensures the app is valid and takes an app name as an argument, not context.
|
||||||
|
func ValidateAppByName(c *cli.Context, appName string) config.App {
|
||||||
|
if AppName != "" {
|
||||||
|
appName = AppName
|
||||||
|
logrus.Debugf("programmatically setting app name to %s", appName)
|
||||||
|
}
|
||||||
|
|
||||||
|
if appName == "" {
|
||||||
|
ShowSubcommandHelpAndError(c, errors.New("no app provided"))
|
||||||
|
}
|
||||||
|
|
||||||
|
app, err := app.Get(appName)
|
||||||
|
if err != nil {
|
||||||
|
logrus.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := recipe.EnsureExists(app.Type); err != nil {
|
||||||
|
logrus.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := ssh.EnsureHostKey(app.Server); err != nil {
|
||||||
|
logrus.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
logrus.Debugf("validated '%s' as app argument", appName)
|
||||||
|
|
||||||
|
return app
|
||||||
|
}
|
||||||
|
|
||||||
// ValidateDomain ensures the domain name arg is valid.
|
// ValidateDomain ensures the domain name arg is valid.
|
||||||
func ValidateDomain(c *cli.Context) (string, error) {
|
func ValidateDomain(c *cli.Context) (string, error) {
|
||||||
domainName := c.Args().First()
|
domainName := c.Args().First()
|
||||||
|
|
|
@ -0,0 +1,101 @@
|
||||||
|
package server
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"os"
|
||||||
|
|
||||||
|
"coopcloud.tech/abra/cli/internal"
|
||||||
|
"coopcloud.tech/abra/pkg/client"
|
||||||
|
"coopcloud.tech/abra/pkg/config"
|
||||||
|
"github.com/docker/docker/api/types"
|
||||||
|
"github.com/docker/docker/api/types/filters"
|
||||||
|
"github.com/sirupsen/logrus"
|
||||||
|
"github.com/urfave/cli/v2"
|
||||||
|
)
|
||||||
|
|
||||||
|
var Taillen string
|
||||||
|
var TaillenFlag = &cli.StringFlag{
|
||||||
|
Name: "tail",
|
||||||
|
Aliases: []string{"t"},
|
||||||
|
Value: "5",
|
||||||
|
Destination: &Taillen,
|
||||||
|
Usage: "change how many lines are shown",
|
||||||
|
}
|
||||||
|
|
||||||
|
var serverLogsCommand = &cli.Command{
|
||||||
|
Name: "logs",
|
||||||
|
Aliases: []string{"l"},
|
||||||
|
ArgsUsage: "<server>",
|
||||||
|
Usage: "show logs from all apps from server",
|
||||||
|
Flags: []cli.Flag{
|
||||||
|
TaillenFlag,
|
||||||
|
internal.StderrFlag,
|
||||||
|
internal.StdoutFlag,
|
||||||
|
internal.HealthcheckFlag,
|
||||||
|
},
|
||||||
|
Action: func(c *cli.Context) error {
|
||||||
|
serverName, err := internal.ValidateServer(c)
|
||||||
|
serviceName := ""
|
||||||
|
if !internal.Stderr && !internal.Stdout && !internal.Healthcheck {
|
||||||
|
internal.Stderr = true
|
||||||
|
internal.Stdout = true
|
||||||
|
internal.Healthcheck = true
|
||||||
|
}
|
||||||
|
|
||||||
|
logrus.Debugf("flags parsed. --stderr: %t, --stdout: %t, --healthcheck: %t", internal.Stderr, internal.Stdout, internal.Healthcheck)
|
||||||
|
if err != nil {
|
||||||
|
logrus.Fatal(err)
|
||||||
|
}
|
||||||
|
appMap, err := config.LoadAppFiles(serverName)
|
||||||
|
if err != nil {
|
||||||
|
logrus.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
logOpts := types.ContainerLogsOptions{
|
||||||
|
Details: false,
|
||||||
|
Follow: false,
|
||||||
|
ShowStderr: internal.Stderr,
|
||||||
|
ShowStdout: internal.Stdout,
|
||||||
|
Tail: Taillen,
|
||||||
|
Timestamps: true,
|
||||||
|
}
|
||||||
|
|
||||||
|
var appFiles []config.App
|
||||||
|
for appname, _ := range appMap {
|
||||||
|
app := internal.ValidateAppByName(c, appname)
|
||||||
|
appFiles = append(appFiles, app)
|
||||||
|
}
|
||||||
|
for _, app := range appFiles {
|
||||||
|
fmt.Println(app)
|
||||||
|
logrus.Debugf("checking logs for: %s", app.Name)
|
||||||
|
cl, err := client.New(app.Server)
|
||||||
|
if err != nil {
|
||||||
|
logrus.Fatal(err)
|
||||||
|
}
|
||||||
|
logrus.Debugf("tailing logs for all services")
|
||||||
|
filters := filters.NewArgs()
|
||||||
|
filters.Add("name", service)
|
||||||
|
serviceOpts := types.ServiceListOptions{Filters: filters}
|
||||||
|
services, err := cl.ServiceList(c.Context, serviceOpts)
|
||||||
|
if err != nil {
|
||||||
|
logrus.Fatal(err)
|
||||||
|
}
|
||||||
|
logs, err := cl.ServiceLogs(c.Context, services[0].ID, logOpts)
|
||||||
|
if err != nil {
|
||||||
|
logrus.Fatal(err)
|
||||||
|
}
|
||||||
|
logrus.Info(app.StackName())
|
||||||
|
for {
|
||||||
|
_, err = io.Copy(os.Stdout, logs)
|
||||||
|
if err == io.EOF {
|
||||||
|
break
|
||||||
|
} else if err != nil {
|
||||||
|
logrus.Fatal(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
logs.Close()
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
},
|
||||||
|
}
|
|
@ -23,5 +23,6 @@ apps, see available flags on "server add" for more.
|
||||||
serverAddCommand,
|
serverAddCommand,
|
||||||
serverListCommand,
|
serverListCommand,
|
||||||
serverRemoveCommand,
|
serverRemoveCommand,
|
||||||
|
serverLogsCommand,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue