forked from toolshed/abra
		
	feat: prototype for app listing
This commit is contained in:
		
							
								
								
									
										2
									
								
								TODO.md
									
									
									
									
									
								
							
							
						
						
									
										2
									
								
								TODO.md
									
									
									
									
									
								
							| @ -12,7 +12,7 @@ Disclaimer!: List is WIP | ||||
|       - [ ] `init` | ||||
|       - [ ] `apps` | ||||
|     - [ ] `abra app` | ||||
|       - [ ] `ls` (XXX: in progress (decentral1se)) | ||||
|       - [x] `ls` | ||||
|       - [ ] `new` | ||||
|       - [ ] `backup` | ||||
|       - [ ] `deploy` | ||||
|  | ||||
| @ -81,8 +81,7 @@ var appListCommand = &cli.Command{ | ||||
| 				// If type flag is set, check for it, if not, Type == "" | ||||
| 				tableRow = []string{app.File.Server, app.Type, app.Domain} | ||||
| 				if Status { | ||||
| 					stackName := strings.ReplaceAll(app.Name, ".", "_") | ||||
| 					if status, ok := statuses[stackName]; ok { | ||||
| 					if status, ok := statuses[app.StackName()]; ok { | ||||
| 						tableRow = append(tableRow, status) | ||||
| 					} else { | ||||
| 						tableRow = append(tableRow, "unknown") | ||||
|  | ||||
| @ -19,6 +19,8 @@ import ( | ||||
| 	"github.com/sirupsen/logrus" | ||||
| ) | ||||
|  | ||||
| const dockerStackNamespace = "com.docker.stack.namespace" | ||||
|  | ||||
| var ABRA_DIR = os.ExpandEnv("$HOME/.abra") | ||||
| var ABRA_SERVER_FOLDER = path.Join(ABRA_DIR, "servers") | ||||
| var APPS_JSON = path.Join(ABRA_DIR, "apps.json") | ||||
| @ -37,6 +39,10 @@ type App struct { | ||||
| 	File   AppFile | ||||
| } | ||||
|  | ||||
| func (a App) StackName() string { | ||||
| 	return strings.ReplaceAll(a.Name, ".", "_") | ||||
| } | ||||
|  | ||||
| type ByServer []App | ||||
|  | ||||
| func (a ByServer) Len() int      { return len(a) } | ||||
| @ -78,7 +84,19 @@ type AppFile struct { | ||||
| 	Server string | ||||
| } | ||||
|  | ||||
| type AppFiles = map[AppName]AppFile | ||||
| type AppFiles map[AppName]AppFile | ||||
|  | ||||
| func (a AppFiles) GetServers() []string { | ||||
| 	var unique []string | ||||
| 	servers := make(map[string]struct{}) | ||||
| 	for _, appFile := range a { | ||||
| 		if _, ok := servers[appFile.Server]; !ok { | ||||
| 			servers[appFile.Server] = struct{}{} | ||||
| 			unique = append(unique, appFile.Server) | ||||
| 		} | ||||
| 	} | ||||
| 	return unique | ||||
| } | ||||
|  | ||||
| func LoadAppFiles(servers ...string) (AppFiles, error) { | ||||
| 	appFiles := make(AppFiles) | ||||
| @ -137,40 +155,42 @@ func GetApps(appFiles AppFiles) ([]App, error) { | ||||
| } | ||||
|  | ||||
| func GetAppStatuses(appFiles AppFiles) (map[string]string, error) { | ||||
| 	statuses := map[string]string{} | ||||
|  | ||||
| 	servers := make(map[string]struct{}) | ||||
| 	for _, appFile := range appFiles { | ||||
| 		if _, ok := servers[appFile.Server]; !ok { | ||||
| 			servers[appFile.Server] = struct{}{} | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	type status struct { | ||||
| 		services []swarm.Service | ||||
| 		err      error | ||||
| 	} | ||||
|  | ||||
| 	servers := appFiles.GetServers() | ||||
| 	ch := make(chan status, len(servers)) | ||||
| 	for server, _ := range servers { | ||||
| 	for _, server := range servers { | ||||
| 		go func(s string) { | ||||
| 			ctx := context.Background() | ||||
| 			cl, err := client.NewClientWithContext(s) | ||||
| 			if err != nil { | ||||
| 				ch <- status{services: []swarm.Service{}, err: nil} | ||||
| 				if strings.Contains(err.Error(), "does not exist") { | ||||
| 					// No local context found, bail out gracefully | ||||
| 					ch <- status{services: []swarm.Service{}, err: nil} | ||||
| 					return | ||||
| 				} | ||||
| 				ch <- status{services: []swarm.Service{}, err: err} | ||||
| 				return | ||||
| 			} | ||||
| 			ctx := context.Background() | ||||
| 			filter := filters.NewArgs() | ||||
| 			filter.Add("label", "com.docker.stack.namespace") | ||||
| 			services, _ := cl.ServiceList(ctx, types.ServiceListOptions{Filters: filter}) | ||||
| 			filter.Add("label", dockerStackNamespace) | ||||
| 			services, err := cl.ServiceList(ctx, types.ServiceListOptions{Filters: filter}) | ||||
| 			if err != nil { | ||||
| 				ch <- status{services: []swarm.Service{}, err: err} | ||||
| 				return | ||||
| 			} | ||||
| 			ch <- status{services: services, err: nil} | ||||
| 		}(server) | ||||
| 	} | ||||
|  | ||||
| 	statuses := map[string]string{} | ||||
| 	for range servers { | ||||
| 		status := <-ch | ||||
| 		for _, service := range status.services { | ||||
| 			name := service.Spec.Labels["com.docker.stack.namespace"] | ||||
| 			name := service.Spec.Labels[dockerStackNamespace] | ||||
| 			if _, ok := statuses[name]; !ok { | ||||
| 				statuses[name] = "deployed" | ||||
| 			} | ||||
|  | ||||
		Reference in New Issue
	
	Block a user