A self-hosted orchestration system crafted for power users. composia.xyz
Something went wrong. Try again.
Go
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205package cli
import ( "fmt"
controllerv1 "forgejo.alexma.top/alexma233/composia/gen/go/proto/composia/controller/v1" "google.golang.org/protobuf/proto")
func (application *app) runNodeStats(args []string) error { if err := requireArgs(args, 1, "composia node stats <node>"); err != nil { return err } response, err := application.client.nodes.GetNodeDockerStats(application.ctx, newRequest(&controllerv1.GetNodeDockerStatsRequest{NodeId: args[0]})) if err != nil { return err } if application.isJSONOutput() { return application.printMessage(response.Msg) } stats := response.Msg.GetStats() if stats == nil { return fmt.Errorf("docker stats for node %q were not found", args[0]) } return application.writeKV([][2]string{ {"containers_total", uintText(stats.GetContainersTotal())}, {"containers_running", uintText(stats.GetContainersRunning())}, {"containers_stopped", uintText(stats.GetContainersStopped())}, {"containers_paused", uintText(stats.GetContainersPaused())}, {"images", uintText(stats.GetImages())}, {"networks", uintText(stats.GetNetworks())}, {"volumes", uintText(stats.GetVolumes())}, {"volumes_size_bytes", uint64Text(stats.GetVolumesSizeBytes())}, {"disks_usage_bytes", uint64Text(stats.GetDisksUsageBytes())}, {"docker_server_version", stats.GetDockerServerVersion()}, })}
func (application *app) runNodeList(args []string) error { if err := requireArgs(args, 0, "composia node list"); err != nil { return err } response, err := application.client.nodes.ListNodes(application.ctx, newRequest(&controllerv1.ListNodesRequest{})) if err != nil { return err } if application.isJSONOutput() { return application.printMessage(response.Msg) } rows := make([][]string, 0, len(response.Msg.GetNodes())) for _, node := range response.Msg.GetNodes() { rows = append(rows, []string{ node.GetNodeId(), node.GetDisplayName(), boolText(node.GetEnabled()), boolText(node.GetIsOnline()), node.GetLastHeartbeat(), }) } return application.writeTable([]string{"NODE", "NAME", "ENABLED", "ONLINE", "LAST_HEARTBEAT"}, rows)}
func (application *app) runNodeGet(args []string) error { if err := requireArgs(args, 1, "composia node get <node>"); err != nil { return err } response, err := application.client.nodes.GetNode(application.ctx, newRequest(&controllerv1.GetNodeRequest{NodeId: args[0]})) if err != nil { return err } if application.isJSONOutput() { return application.printMessage(response.Msg) } node := response.Msg.GetNode() if node == nil { return fmt.Errorf("node %q was not found", args[0]) } caddySyncEnabled, caddySyncReason := capabilityText(node.GetActions().GetCaddySync()) caddyReloadEnabled, caddyReloadReason := capabilityText(node.GetActions().GetCaddyReload()) rusticEnabled, rusticReason := capabilityText(node.GetActions().GetRusticMaintenance()) return application.writeKV([][2]string{ {"node_id", node.GetNodeId()}, {"display_name", node.GetDisplayName()}, {"enabled", boolText(node.GetEnabled())}, {"is_online", boolText(node.GetIsOnline())}, {"last_heartbeat", node.GetLastHeartbeat()}, {"caddy_sync_enabled", boolText(caddySyncEnabled)}, {"caddy_sync_reason", caddySyncReason}, {"caddy_reload_enabled", boolText(caddyReloadEnabled)}, {"caddy_reload_reason", caddyReloadReason}, {"rustic_maintenance_enabled", boolText(rusticEnabled)}, {"rustic_maintenance_reason", rusticReason}, })}
func (application *app) runNodeTasks(args []string) error { fs := newCommandFlagSet("node tasks") status := fs.String("status", "", "status filter") pageValues, _ := parsePageFlags(fs) if err := fs.Parse(args); err != nil { return err } if err := requireArgs(fs.Args(), 1, "composia node tasks [--status status] <node>"); err != nil { return err } pageSize, page, err := pageValues() if err != nil { return err } response, err := application.client.tasks.ListTasks(application.ctx, newRequest(&controllerv1.ListTasksRequest{NodeId: []string{fs.Arg(0)}, Status: taskStatusesFromTexts([]string{*status}), PageSize: pageSize, Page: page})) if err != nil { return err } if application.isJSONOutput() { return application.printMessage(response.Msg) } rows := make([][]string, 0, len(response.Msg.GetTasks())) for _, task := range response.Msg.GetTasks() { rows = append(rows, []string{task.GetTaskId(), taskTypeText(task.GetType()), taskStatusText(task.GetStatus()), task.GetServiceName(), task.GetNodeId(), formatProtoTimestamp(task.GetCreatedAt())}) } if err := application.writeTable([]string{"TASK", "TYPE", "STATUS", "SERVICE", "NODE", "CREATED"}, rows); err != nil { return err } return application.writeCount("total_count", response.Msg.GetTotalCount())}
func (application *app) runNodeReloadCaddy(args []string) error { fs := newCommandFlagSet("node reload-caddy") waitOptions := addWaitFlags(fs) if err := fs.Parse(args); err != nil { return err } if err := requireArgs(fs.Args(), 1, "composia node reload-caddy [--wait] [--follow] [--timeout duration] <node>"); err != nil { return err } response, err := application.client.nodeCommands.ReloadNodeCaddy(application.ctx, newRequest(&controllerv1.ReloadNodeCaddyRequest{NodeId: fs.Arg(0)})) if err != nil { return err } return application.printTaskIDWithWait(response.Msg, response.Msg.GetTaskId(), waitOptions)}
func (application *app) runNodeSyncCaddyFiles(args []string) error { fs := newCommandFlagSet("node sync-caddy-files") serviceName := fs.String("service", "", "service name filter") fullRebuild := fs.Bool("full-rebuild", false, "force a full Caddy file rebuild") waitOptions := addWaitFlags(fs) if err := fs.Parse(args); err != nil { return err } if err := requireArgs(fs.Args(), 1, "composia node sync-caddy-files [--wait] [--follow] [--timeout duration] [--service name] [--full-rebuild] <node>"); err != nil { return err } response, err := application.client.nodeCommands.SyncNodeCaddyFiles(application.ctx, newRequest(&controllerv1.SyncNodeCaddyFilesRequest{NodeId: fs.Arg(0), ServiceName: *serviceName, FullRebuild: *fullRebuild})) if err != nil { return err } return application.printTaskIDWithWait(response.Msg, response.Msg.GetTaskId(), waitOptions)}
func (application *app) runNodePrune(args []string) error { fs := newCommandFlagSet("node prune") target := fs.String("target", "all", "Docker prune target") yes := addYesFlag(fs) waitOptions := addWaitFlags(fs) if err := fs.Parse(args); err != nil { return err } if err := requireArgs(fs.Args(), 1, "composia node prune [--yes] [--wait] [--follow] [--timeout duration] [--target all|container|image|network|volume] <node>"); err != nil { return err } if err := application.confirmDestructive(fmt.Sprintf("This will prune %s Docker resources on node %q.", *target, fs.Arg(0)), yes); err != nil { return err } response, err := application.client.nodeCommands.PruneNodeDocker(application.ctx, newRequest(&controllerv1.PruneNodeDockerRequest{NodeId: fs.Arg(0), Target: *target})) if err != nil { return err } return application.printTaskIDWithWait(response.Msg, response.Msg.GetTaskId(), waitOptions)}
func (application *app) printTaskID(message proto.Message, taskID string) error { if application.isJSONOutput() { return application.printMessage(message) } return application.writeKV([][2]string{{"task_id", taskID}})}
func (application *app) printTaskIDWithWait(message proto.Message, taskID string, options waitOptions) error { if err := application.printTaskID(message, taskID); err != nil { return err } if !options.shouldWait() { return nil } return application.waitTask(taskID, options)}
func capabilityText(capability *controllerv1.Capability) (bool, string) { if capability == nil { return false, "" } return capability.GetEnabled(), capabilityReasonText(capability.GetReasonCode())}