Compare commits
	
		
			2 Commits
		
	
	
		
			0.8.0-rc1-
			...
			app-error
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 
						
						
							
						
						ed859c0243
	
				 | 
					
					
						|||
| 
						
						
							
						
						236d0f5892
	
				 | 
					
					
						
@ -4,74 +4,54 @@ import (
 | 
			
		||||
	"fmt"
 | 
			
		||||
	"io"
 | 
			
		||||
	"os"
 | 
			
		||||
	"sync"
 | 
			
		||||
 | 
			
		||||
	"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"
 | 
			
		||||
	dockerClient "github.com/docker/docker/client"
 | 
			
		||||
	"github.com/sirupsen/logrus"
 | 
			
		||||
	"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{
 | 
			
		||||
	Name:      "logs",
 | 
			
		||||
	Aliases:   []string{"l"},
 | 
			
		||||
	ArgsUsage: "[<service>]",
 | 
			
		||||
	Usage:     "Tail app logs",
 | 
			
		||||
	Flags: []cli.Flag{
 | 
			
		||||
		internal.StderrFlag,
 | 
			
		||||
		internal.StdoutFlag,
 | 
			
		||||
		internal.HealthcheckFlag,
 | 
			
		||||
	},
 | 
			
		||||
	Action: func(c *cli.Context) error {
 | 
			
		||||
		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)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			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)
 | 
			
		||||
		if serviceName == "" {
 | 
			
		||||
			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)
 | 
			
		||||
 | 
			
		||||
@ -87,14 +67,6 @@ var appLogsCommand = &cli.Command{
 | 
			
		||||
			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)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			logrus.Fatal(err)
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										68
									
								
								cli/internal/logs.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										68
									
								
								cli/internal/logs.go
									
									
									
									
									
										Normal file
									
								
							@ -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
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// 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.
 | 
			
		||||
func ValidateDomain(c *cli.Context) (string, error) {
 | 
			
		||||
	domainName := c.Args().First()
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										101
									
								
								cli/server/logs.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										101
									
								
								cli/server/logs.go
									
									
									
									
									
										Normal file
									
								
							@ -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,
 | 
			
		||||
		serverListCommand,
 | 
			
		||||
		serverRemoveCommand,
 | 
			
		||||
		serverLogsCommand,
 | 
			
		||||
	},
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
		Reference in New Issue
	
	Block a user