forked from toolshed/abra
		
	Compare commits
	
		
			2 Commits
		
	
	
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| ed859c0243 | |||
| 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) | ||||||
|  | |||||||
							
								
								
									
										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 | 	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() | ||||||
|  | |||||||
							
								
								
									
										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, | 		serverAddCommand, | ||||||
| 		serverListCommand, | 		serverListCommand, | ||||||
| 		serverRemoveCommand, | 		serverRemoveCommand, | ||||||
|  | 		serverLogsCommand, | ||||||
| 	}, | 	}, | ||||||
| } | } | ||||||
|  | |||||||
		Reference in New Issue
	
	Block a user