Compare commits
	
		
			2 Commits
		
	
	
		
			0.4.0-alph
			...
			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