// Package model holds the master's domain types shared by storage, the agent // hub and the web UI. package model import ( "errors" "strconv" "strings" "time" "github.com/shcizo/package-updater/internal/protocol" ) // Sentinel errors returned by storage. var ( ErrNotFound = errors.New("not found") ErrConflict = errors.New("already exists") ErrRevoked = errors.New("agent revoked") ) // Agent is a registered agent. Whether it is connected right now is held in // memory by the hub, not here. type Agent struct { ID int64 Name string Hostname string AgentVersion string SwarmManager bool LastSeenAt *time.Time RevokedAt *time.Time CreatedAt time.Time } // Service is one service as last reported by an agent. type Service struct { ID int64 Kind protocol.Kind LocationKey string AgentID *int64 AgentName string ComposeProject string ComposeService string WorkingDir string SwarmClusterID string SwarmService string ContainerName string ImageRepo string ActualRef string ActualDigest string Status string Self bool UpdateMode string FirstSeenAt time.Time UpdatedAt time.Time } // DisplayName is the human-facing name of the service. func (s Service) DisplayName() string { switch s.Kind { case protocol.KindCompose: return s.ComposeProject + "/" + s.ComposeService case protocol.KindSwarm: return s.SwarmService default: return s.ContainerName } } // Session is a logged-in browser session. type Session struct { ID string Subject string Name string Email string CSRFToken string ExpiresAt time.Time } // LocationKey turns an agent-relative protocol key into the fleet-wide key // stored in services.location_key. Compose services and containers belong to // the agent's machine; Swarm services belong to the cluster, so two manager // agents in one cluster report the same row. func LocationKey(agentID int64, clusterID, agentKey string) string { kind, rest, _ := strings.Cut(agentKey, "|") if kind == string(protocol.KindSwarm) { return kind + "|" + clusterID + "|" + rest } return kind + "|" + strconv.FormatInt(agentID, 10) + "|" + rest }