← back to keneo__docker-dynamic-limits

Function bodies 128 total

All specs Real LLM only Function bodies
enforcement.Manager.checkAndEnforce method · go · L125-L167 (43 LOC)
internal/enforcement/enforcement.go
func (m *Manager) checkAndEnforce(ctx context.Context, containerID, dockerID string) {
	// Check if container is still running
	running, err := m.docker.IsContainerRunning(ctx, dockerID)
	if err != nil || !running {
		return
	}

	limits, err := m.store.GetAllLimits(containerID)
	if err != nil {
		log.Printf("[enforcement] error getting limits for %s: %v", containerID, err)
		return
	}

	// Find cgroup path
	cgroupPath, cgroupErr := m.cgroup.FindCgroupPath(dockerID)

	// Check each limit type
	for _, lt := range model.AllLimitTypes {
		limit, hasLimit := limits[lt]
		if !hasLimit || limit == 0 {
			continue
		}

		usage, err := m.getCurrentUsage(ctx, containerID, dockerID, lt, cgroupPath, cgroupErr)
		if err != nil {
			continue
		}

		// Persist usage to store
		m.store.SetUsage(containerID, lt, usage)

		exceeded := usage >= limit
		m.mu.Lock()
		wasEnforced := m.enforced[containerID][lt]
		m.mu.Unlock()

		if exceeded && !wasEnforced {
			m.enforce(ctx, containerID, dockerID, lt, cgr
enforcement.Manager.getCurrentUsage method · go · L169-L228 (60 LOC)
internal/enforcement/enforcement.go
func (m *Manager) getCurrentUsage(ctx context.Context, containerID, dockerID string, lt model.LimitType, cgroupPath string, cgroupErr error) (int64, error) {
	switch lt {
	case model.LimitCPU:
		if cgroupErr != nil {
			return 0, cgroupErr
		}
		usec, err := m.cgroup.CPUUsageMicroseconds(cgroupPath)
		if err != nil {
			return 0, err
		}
		return usec / 1_000_000, nil // convert to seconds

	case model.LimitRAM:
		if cgroupErr != nil {
			return 0, cgroupErr
		}
		return m.cgroup.MemoryCurrent(cgroupPath)

	case model.LimitDisk:
		return m.docker.GetContainerDiskUsage(ctx, dockerID)

	case model.LimitNetwork:
		if cgroupErr != nil {
			return 0, cgroupErr
		}
		// Try to get network stats from stored veth name or default
		// For simplicity, read from stored usage + incremental
		usage, _ := m.store.GetUsage(containerID, lt)
		return usage, nil

	case model.LimitDiskIOByte:
		if cgroupErr != nil {
			return 0, cgroupErr
		}
		stats, err := m.cgroup.ReadIOStat(cgroupPath)
		if err != ni
enforcement.Manager.enforce method · go · L230-L284 (55 LOC)
internal/enforcement/enforcement.go
func (m *Manager) enforce(ctx context.Context, containerID, dockerID string, lt model.LimitType, cgroupPath string) {
	var err error
	switch lt {
	case model.LimitCPU:
		err = m.docker.PauseContainer(ctx, dockerID)
		if err == nil {
			log.Printf("[enforcement] paused container %s: CPU limit exceeded", containerID)
		}

	case model.LimitRAM:
		// RAM is enforced by the kernel via memory.max — we just update it
		limit, _ := m.store.GetLimit(containerID, lt)
		err = m.docker.UpdateMemoryLimit(ctx, dockerID, limit)
		if err == nil {
			log.Printf("[enforcement] set memory limit for %s to %d bytes", containerID, limit)
		}

	case model.LimitDisk:
		err = m.docker.PauseContainer(ctx, dockerID)
		if err == nil {
			log.Printf("[enforcement] paused container %s: disk limit exceeded", containerID)
		}

	case model.LimitNetwork:
		err = m.docker.DisconnectNetwork(ctx, dockerID)
		if err == nil {
			log.Printf("[enforcement] disconnected network for %s: network limit exceeded", containerID)
		}
enforcement.Manager.release method · go · L286-L345 (60 LOC)
internal/enforcement/enforcement.go
func (m *Manager) release(ctx context.Context, containerID, dockerID string, lt model.LimitType, cgroupPath string) {
	var err error
	switch lt {
	case model.LimitCPU:
		paused, _ := m.docker.IsContainerPaused(ctx, dockerID)
		if paused {
			// Only unpause if no other limit type is also enforcing pause
			if !m.isOtherPauseActive(containerID, lt) {
				err = m.docker.UnpauseContainer(ctx, dockerID)
				if err == nil {
					log.Printf("[enforcement] resumed container %s: CPU limit increased", containerID)
				}
			}
		}

	case model.LimitRAM:
		limit, _ := m.store.GetLimit(containerID, lt)
		err = m.docker.UpdateMemoryLimit(ctx, dockerID, limit)
		if err == nil {
			log.Printf("[enforcement] updated memory limit for %s to %d bytes", containerID, limit)
		}

	case model.LimitDisk:
		paused, _ := m.docker.IsContainerPaused(ctx, dockerID)
		if paused && !m.isOtherPauseActive(containerID, lt) {
			err = m.docker.UnpauseContainer(ctx, dockerID)
			if err == nil {
				log.Printf("[enforcemen
enforcement.Manager.isOtherPauseActive method · go · L348-L358 (11 LOC)
internal/enforcement/enforcement.go
func (m *Manager) isOtherPauseActive(containerID string, except model.LimitType) bool {
	m.mu.Lock()
	defer m.mu.Unlock()
	pauseTypes := []model.LimitType{model.LimitCPU, model.LimitDisk}
	for _, lt := range pauseTypes {
		if lt != except && m.enforced[containerID][lt] {
			return true
		}
	}
	return false
}
enforcement.Manager.StartAll method · go · L361-L370 (10 LOC)
internal/enforcement/enforcement.go
func (m *Manager) StartAll() error {
	containers, err := m.store.ListContainers()
	if err != nil {
		return err
	}
	for _, c := range containers {
		m.StartContainer(c.ID, c.DockerID)
	}
	return nil
}
enforcement.Manager.StopAll method · go · L373-L380 (8 LOC)
internal/enforcement/enforcement.go
func (m *Manager) StopAll() {
	m.mu.Lock()
	defer m.mu.Unlock()
	for id, cancel := range m.workers {
		cancel()
		delete(m.workers, id)
	}
}
Repobility — same analyzer, your code, free for public repos · /scan/
proxy.NewSpendingTracker function · go · L47-L55 (9 LOC)
internal/proxy/proxy.go
func NewSpendingTracker(onUpdate func(containerID string, totalCents int64)) *SpendingTracker {
	return &SpendingTracker{
		containerByAddr:  make(map[string]string),
		spending:         make(map[string]int64),
		budgets:          make(map[string]int64),
		prices:           defaultPrices(),
		onSpendingUpdate: onUpdate,
	}
}
proxy.defaultPrices function · go · L57-L72 (16 LOC)
internal/proxy/proxy.go
func defaultPrices() map[string]ModelPricing {
	// Prices in micro-cents per token (1 cent = 1_000_000 micro-cents)
	// These are approximate — users can override via config
	return map[string]ModelPricing{
		// OpenAI
		"gpt-4":         {InputPerToken: 3000, OutputPerToken: 6000},   // $0.03/$0.06 per 1K
		"gpt-4-turbo":   {InputPerToken: 1000, OutputPerToken: 3000},   // $0.01/$0.03 per 1K
		"gpt-4o":        {InputPerToken: 250, OutputPerToken: 1000},    // $0.0025/$0.01 per 1K
		"gpt-4o-mini":   {InputPerToken: 15, OutputPerToken: 60},       // $0.00015/$0.0006 per 1K
		"gpt-3.5-turbo": {InputPerToken: 50, OutputPerToken: 150},      // $0.0005/$0.0015 per 1K
		// Anthropic
		"claude-3-opus":   {InputPerToken: 1500, OutputPerToken: 7500},  // $0.015/$0.075 per 1K
		"claude-3-sonnet": {InputPerToken: 300, OutputPerToken: 1500},   // $0.003/$0.015 per 1K
		"claude-3-haiku":  {InputPerToken: 25, OutputPerToken: 125},     // $0.00025/$0.00125 per 1K
	}
}
proxy.SpendingTracker.RegisterContainer method · go · L76-L97 (22 LOC)
internal/proxy/proxy.go
func (st *SpendingTracker) RegisterContainer(containerID string, budget int64, existingSpending int64) (string, error) {
	// Start a per-container proxy listener
	listener, err := net.Listen("tcp", "0.0.0.0:0")
	if err != nil {
		return "", fmt.Errorf("listen: %w", err)
	}
	addr := listener.Addr().String()

	st.mu.Lock()
	st.containerByAddr[addr] = containerID
	st.spending[containerID] = existingSpending
	st.budgets[containerID] = budget
	st.mu.Unlock()

	proxy := &http.Server{
		Handler: st.proxyHandler(containerID),
	}
	go proxy.Serve(listener)

	log.Printf("[proxy] started proxy for container %s on %s (budget: %d cents)", containerID, addr, budget)
	return addr, nil
}
proxy.SpendingTracker.proxyHandler method · go · L120-L180 (61 LOC)
internal/proxy/proxy.go
func (st *SpendingTracker) proxyHandler(containerID string) http.Handler {
	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		// Check if budget is exceeded before proxying
		st.mu.RLock()
		budget := st.budgets[containerID]
		spent := st.spending[containerID]
		st.mu.RUnlock()

		isAPICall := st.isTrackedAPI(r.Host)

		if isAPICall && budget > 0 && spent >= budget {
			http.Error(w, `{"error":"spending budget exceeded"}`, http.StatusTooManyRequests)
			return
		}

		// Forward the request
		outReq, err := http.NewRequestWithContext(r.Context(), r.Method, r.URL.String(), r.Body)
		if err != nil {
			http.Error(w, err.Error(), http.StatusBadGateway)
			return
		}
		outReq.Header = r.Header.Clone()
		outReq.ContentLength = r.ContentLength

		transport := st.transport
		if transport == nil {
			transport = http.DefaultTransport
		}
		resp, err := transport.RoundTrip(outReq)
		if err != nil {
			http.Error(w, err.Error(), http.StatusBadGateway)
			return
		}
		defer 
proxy.IsTrackedAPIHost function · go · L183-L194 (12 LOC)
internal/proxy/proxy.go
func IsTrackedAPIHost(host string) bool {
	tracked := []string{
		"api.openai.com",
		"api.anthropic.com",
	}
	for _, h := range tracked {
		if strings.Contains(host, h) {
			return true
		}
	}
	return false
}
proxy.SpendingTracker.trackSpending method · go · L211-L247 (37 LOC)
internal/proxy/proxy.go
func (st *SpendingTracker) trackSpending(containerID string, host string, body []byte) {
	var resp apiUsage
	if err := json.Unmarshal(body, &resp); err != nil {
		return
	}

	inputTokens := resp.Usage.PromptTokens + resp.Usage.InputTokens
	outputTokens := resp.Usage.CompletionTokens + resp.Usage.OutputTokens

	if inputTokens == 0 && outputTokens == 0 {
		return
	}

	// Find pricing for this model
	modelName := normalizeModelName(resp.Model)
	st.mu.RLock()
	pricing, ok := st.prices[modelName]
	st.mu.RUnlock()
	if !ok {
		// Use a conservative default
		pricing = ModelPricing{InputPerToken: 1000, OutputPerToken: 3000}
	}

	costCents := CalculateSpendingCents(inputTokens, outputTokens, pricing)

	st.mu.Lock()
	st.spending[containerID] += costCents
	newTotal := st.spending[containerID]
	st.mu.Unlock()

	if st.onSpendingUpdate != nil {
		st.onSpendingUpdate(containerID, newTotal)
	}

	log.Printf("[proxy] container %s: %d input + %d output tokens (%s) = %d cents (total: %d)",
		containerID, 
proxy.CalculateSpendingCents function · go · L250-L257 (8 LOC)
internal/proxy/proxy.go
func CalculateSpendingCents(inputTokens, outputTokens int64, pricing ModelPricing) int64 {
	costMicroCents := inputTokens*pricing.InputPerToken + outputTokens*pricing.OutputPerToken
	costCents := costMicroCents / 1_000_000
	if costCents == 0 && costMicroCents > 0 {
		costCents = 1 // minimum 1 cent charge to avoid free-riding
	}
	return costCents
}
proxy.normalizeModelName function · go · L259-L273 (15 LOC)
internal/proxy/proxy.go
func normalizeModelName(model string) string {
	// Strip date suffixes and version details
	model = strings.ToLower(model)
	// Map known prefixes
	prefixes := []string{
		"gpt-4o-mini", "gpt-4o", "gpt-4-turbo", "gpt-4", "gpt-3.5-turbo",
		"claude-3-opus", "claude-3-sonnet", "claude-3-haiku",
	}
	for _, p := range prefixes {
		if strings.HasPrefix(model, p) {
			return p
		}
	}
	return model
}
Open data scored by Repobility · https://repobility.com
proxy.SpendingTracker.ConnectHandler method · go · L276-L284 (9 LOC)
internal/proxy/proxy.go
func (st *SpendingTracker) ConnectHandler(containerID string) http.Handler {
	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		if r.Method == http.MethodConnect {
			st.handleConnect(containerID, w, r)
			return
		}
		st.proxyHandler(containerID).ServeHTTP(w, r)
	})
}
proxy.SpendingTracker.handleConnect method · go · L286-L324 (39 LOC)
internal/proxy/proxy.go
func (st *SpendingTracker) handleConnect(containerID string, w http.ResponseWriter, r *http.Request) {
	// For CONNECT (HTTPS), we just tunnel the connection
	// We can't inspect the content, but we can block by host
	st.mu.RLock()
	budget := st.budgets[containerID]
	spent := st.spending[containerID]
	st.mu.RUnlock()

	if st.isTrackedAPI(r.Host) && budget > 0 && spent >= budget {
		http.Error(w, "spending budget exceeded", http.StatusTooManyRequests)
		return
	}

	destConn, err := net.Dial("tcp", r.Host)
	if err != nil {
		http.Error(w, err.Error(), http.StatusBadGateway)
		return
	}
	defer destConn.Close()

	hijacker, ok := w.(http.Hijacker)
	if !ok {
		http.Error(w, "hijacking not supported", http.StatusInternalServerError)
		return
	}

	w.WriteHeader(http.StatusOK)
	clientConn, _, err := hijacker.Hijack()
	if err != nil {
		return
	}
	defer clientConn.Close()

	// Bidirectional copy
	done := make(chan struct{}, 2)
	go func() { io.Copy(destConn, clientConn); done <- struct{}{} }()
	g
proxy.SpendingTracker.LoadPrices method · go · L327-L342 (16 LOC)
internal/proxy/proxy.go
func (st *SpendingTracker) LoadPrices(r io.Reader) error {
	var prices map[string]ModelPricing
	data, err := io.ReadAll(r)
	if err != nil {
		return err
	}
	if err := json.Unmarshal(data, &prices); err != nil {
		return err
	}
	st.mu.Lock()
	defer st.mu.Unlock()
	for k, v := range prices {
		st.prices[k] = v
	}
	return nil
}
proxy.SpendingTracker.SetResolveOverrides method · go · L347-L359 (13 LOC)
internal/proxy/proxy.go
func (st *SpendingTracker) SetResolveOverrides(overrides map[string]string) {
	st.transport = &http.Transport{
		DialContext: func(ctx context.Context, network, addr string) (net.Conn, error) {
			host, port, err := net.SplitHostPort(addr)
			if err == nil {
				if override, ok := overrides[host]; ok {
					addr = net.JoinHostPort(override, port)
				}
			}
			return (&net.Dialer{}).DialContext(ctx, network, addr)
		},
	}
}
store.New function · go · L38-L49 (12 LOC)
internal/store/store.go
func New(dbPath string) (*Store, error) {
	db, err := sql.Open("sqlite3", dbPath+"?_journal_mode=WAL&_busy_timeout=5000")
	if err != nil {
		return nil, fmt.Errorf("open db: %w", err)
	}
	s := &Store{db: db}
	if err := s.migrate(); err != nil {
		db.Close()
		return nil, fmt.Errorf("migrate: %w", err)
	}
	return s, nil
}
store.Store.migrate method · go · L51-L80 (30 LOC)
internal/store/store.go
func (s *Store) migrate() error {
	stmts := []string{
		`CREATE TABLE IF NOT EXISTS containers (
			id TEXT PRIMARY KEY,
			docker_id TEXT NOT NULL,
			name TEXT NOT NULL DEFAULT '',
			registered_at TEXT NOT NULL
		)`,
		`CREATE TABLE IF NOT EXISTS limits (
			container_id TEXT NOT NULL,
			type TEXT NOT NULL,
			value INTEGER NOT NULL DEFAULT 0,
			PRIMARY KEY (container_id, type),
			FOREIGN KEY (container_id) REFERENCES containers(id)
		)`,
		`CREATE TABLE IF NOT EXISTS usage (
			container_id TEXT NOT NULL,
			type TEXT NOT NULL,
			value INTEGER NOT NULL DEFAULT 0,
			PRIMARY KEY (container_id, type),
			FOREIGN KEY (container_id) REFERENCES containers(id)
		)`,
	}
	for _, stmt := range stmts {
		if _, err := s.db.Exec(stmt); err != nil {
			return fmt.Errorf("exec %q: %w", stmt[:40], err)
		}
	}
	return nil
}
store.Store.RegisterContainer method · go · L88-L106 (19 LOC)
internal/store/store.go
func (s *Store) RegisterContainer(dockerID, name string) (*model.Container, error) {
	s.mu.Lock()
	defer s.mu.Unlock()

	c := &model.Container{
		ID:           dockerID[:12],
		DockerID:     dockerID,
		Name:         name,
		RegisteredAt: time.Now().UTC(),
	}
	_, err := s.db.Exec(
		`INSERT OR REPLACE INTO containers (id, docker_id, name, registered_at) VALUES (?, ?, ?, ?)`,
		c.ID, c.DockerID, c.Name, c.RegisteredAt.Format(time.RFC3339),
	)
	if err != nil {
		return nil, fmt.Errorf("insert container: %w", err)
	}
	return c, nil
}
store.Store.GetContainer method · go · L109-L121 (13 LOC)
internal/store/store.go
func (s *Store) GetContainer(id string) (*model.Container, error) {
	row := s.db.QueryRow(`SELECT id, docker_id, name, registered_at FROM containers WHERE id = ?`, id)
	c := &model.Container{}
	var regAt string
	if err := row.Scan(&c.ID, &c.DockerID, &c.Name, &regAt); err != nil {
		if err == sql.ErrNoRows {
			return nil, fmt.Errorf("container %s not found", id)
		}
		return nil, err
	}
	c.RegisteredAt, _ = time.Parse(time.RFC3339, regAt)
	return c, nil
}
All rows above produced by Repobility · https://repobility.com
store.Store.ListContainers method · go · L124-L142 (19 LOC)
internal/store/store.go
func (s *Store) ListContainers() ([]model.Container, error) {
	rows, err := s.db.Query(`SELECT id, docker_id, name, registered_at FROM containers ORDER BY registered_at`)
	if err != nil {
		return nil, err
	}
	defer rows.Close()

	var result []model.Container
	for rows.Next() {
		var c model.Container
		var regAt string
		if err := rows.Scan(&c.ID, &c.DockerID, &c.Name, &regAt); err != nil {
			return nil, err
		}
		c.RegisteredAt, _ = time.Parse(time.RFC3339, regAt)
		result = append(result, c)
	}
	return result, rows.Err()
}
store.Store.RemoveContainer method · go · L145-L159 (15 LOC)
internal/store/store.go
func (s *Store) RemoveContainer(id string) error {
	s.mu.Lock()
	defer s.mu.Unlock()

	tx, err := s.db.Begin()
	if err != nil {
		return err
	}
	defer tx.Rollback()

	tx.Exec(`DELETE FROM usage WHERE container_id = ?`, id)
	tx.Exec(`DELETE FROM limits WHERE container_id = ?`, id)
	tx.Exec(`DELETE FROM containers WHERE id = ?`, id)
	return tx.Commit()
}
store.Store.SetLimit method · go · L162-L171 (10 LOC)
internal/store/store.go
func (s *Store) SetLimit(containerID string, limitType model.LimitType, value int64) error {
	s.mu.Lock()
	defer s.mu.Unlock()

	_, err := s.db.Exec(
		`INSERT OR REPLACE INTO limits (container_id, type, value) VALUES (?, ?, ?)`,
		containerID, string(limitType), value,
	)
	return err
}
store.Store.GetLimit method · go · L174-L187 (14 LOC)
internal/store/store.go
func (s *Store) GetLimit(containerID string, limitType model.LimitType) (int64, error) {
	row := s.db.QueryRow(
		`SELECT value FROM limits WHERE container_id = ? AND type = ?`,
		containerID, string(limitType),
	)
	var val int64
	if err := row.Scan(&val); err != nil {
		if err == sql.ErrNoRows {
			return 0, nil
		}
		return 0, err
	}
	return val, nil
}
store.Store.GetAllLimits method · go · L190-L209 (20 LOC)
internal/store/store.go
func (s *Store) GetAllLimits(containerID string) (map[model.LimitType]int64, error) {
	rows, err := s.db.Query(
		`SELECT type, value FROM limits WHERE container_id = ?`, containerID,
	)
	if err != nil {
		return nil, err
	}
	defer rows.Close()

	result := make(map[model.LimitType]int64)
	for rows.Next() {
		var t string
		var v int64
		if err := rows.Scan(&t, &v); err != nil {
			return nil, err
		}
		result[model.LimitType(t)] = v
	}
	return result, rows.Err()
}
store.Store.SetUsage method · go · L212-L221 (10 LOC)
internal/store/store.go
func (s *Store) SetUsage(containerID string, limitType model.LimitType, value int64) error {
	s.mu.Lock()
	defer s.mu.Unlock()

	_, err := s.db.Exec(
		`INSERT OR REPLACE INTO usage (container_id, type, value) VALUES (?, ?, ?)`,
		containerID, string(limitType), value,
	)
	return err
}
store.Store.GetUsage method · go · L224-L237 (14 LOC)
internal/store/store.go
func (s *Store) GetUsage(containerID string, limitType model.LimitType) (int64, error) {
	row := s.db.QueryRow(
		`SELECT value FROM usage WHERE container_id = ? AND type = ?`,
		containerID, string(limitType),
	)
	var val int64
	if err := row.Scan(&val); err != nil {
		if err == sql.ErrNoRows {
			return 0, nil
		}
		return 0, err
	}
	return val, nil
}
store.Store.GetAllUsage method · go · L240-L259 (20 LOC)
internal/store/store.go
func (s *Store) GetAllUsage(containerID string) (map[model.LimitType]int64, error) {
	rows, err := s.db.Query(
		`SELECT type, value FROM usage WHERE container_id = ?`, containerID,
	)
	if err != nil {
		return nil, err
	}
	defer rows.Close()

	result := make(map[model.LimitType]int64)
	for rows.Next() {
		var t string
		var v int64
		if err := rows.Scan(&t, &v); err != nil {
			return nil, err
		}
		result[model.LimitType(t)] = v
	}
	return result, rows.Err()
}
Want this analysis on your repo? https://repobility.com/scan/
store.Store.AddUsage method · go · L262-L272 (11 LOC)
internal/store/store.go
func (s *Store) AddUsage(containerID string, limitType model.LimitType, delta int64) error {
	s.mu.Lock()
	defer s.mu.Unlock()

	_, err := s.db.Exec(
		`INSERT INTO usage (container_id, type, value) VALUES (?, ?, ?)
		 ON CONFLICT(container_id, type) DO UPDATE SET value = value + ?`,
		containerID, string(limitType), delta, delta,
	)
	return err
}
store.Store.CopyLimits method · go · L275-L285 (11 LOC)
internal/store/store.go
func (s *Store) CopyLimits(fromID, toID string) error {
	s.mu.Lock()
	defer s.mu.Unlock()

	_, err := s.db.Exec(
		`INSERT OR REPLACE INTO limits (container_id, type, value)
		 SELECT ?, type, value FROM limits WHERE container_id = ?`,
		toID, fromID,
	)
	return err
}
store.Store.ResolveContainerID method · go · L288-L309 (22 LOC)
internal/store/store.go
func (s *Store) ResolveContainerID(query string) (string, error) {
	// Try exact match on ID first
	row := s.db.QueryRow(`SELECT id FROM containers WHERE id = ?`, query)
	var id string
	if err := row.Scan(&id); err == nil {
		return id, nil
	}

	// Try prefix match on docker_id
	row = s.db.QueryRow(`SELECT id FROM containers WHERE docker_id LIKE ? LIMIT 1`, query+"%")
	if err := row.Scan(&id); err == nil {
		return id, nil
	}

	// Try name match
	row = s.db.QueryRow(`SELECT id FROM containers WHERE name = ?`, query)
	if err := row.Scan(&id); err == nil {
		return id, nil
	}

	return "", fmt.Errorf("container %q not found", query)
}
testutil.NewMockStore function · go · L23-L29 (7 LOC)
internal/testutil/mocks.go
func NewMockStore() *MockStore {
	return &MockStore{
		Containers: make(map[string]*model.Container),
		Limits:     make(map[string]map[model.LimitType]int64),
		Usages:     make(map[string]map[model.LimitType]int64),
	}
}
testutil.MockStore.RegisterContainer method · go · L31-L41 (11 LOC)
internal/testutil/mocks.go
func (s *MockStore) RegisterContainer(dockerID, name string) (*model.Container, error) {
	s.mu.Lock()
	defer s.mu.Unlock()
	id := dockerID
	if len(dockerID) >= 12 {
		id = dockerID[:12]
	}
	c := &model.Container{ID: id, DockerID: dockerID, Name: name}
	s.Containers[id] = c
	return c, nil
}
testutil.MockStore.GetContainer method · go · L43-L51 (9 LOC)
internal/testutil/mocks.go
func (s *MockStore) GetContainer(id string) (*model.Container, error) {
	s.mu.Lock()
	defer s.mu.Unlock()
	c, ok := s.Containers[id]
	if !ok {
		return nil, fmt.Errorf("container %s not found", id)
	}
	return c, nil
}
testutil.MockStore.ListContainers method · go · L53-L61 (9 LOC)
internal/testutil/mocks.go
func (s *MockStore) ListContainers() ([]model.Container, error) {
	s.mu.Lock()
	defer s.mu.Unlock()
	var result []model.Container
	for _, c := range s.Containers {
		result = append(result, *c)
	}
	return result, nil
}
testutil.MockStore.RemoveContainer method · go · L63-L70 (8 LOC)
internal/testutil/mocks.go
func (s *MockStore) RemoveContainer(id string) error {
	s.mu.Lock()
	defer s.mu.Unlock()
	delete(s.Containers, id)
	delete(s.Limits, id)
	delete(s.Usages, id)
	return nil
}
Repobility — same analyzer, your code, free for public repos · /scan/
testutil.MockStore.SetLimit method · go · L72-L80 (9 LOC)
internal/testutil/mocks.go
func (s *MockStore) SetLimit(containerID string, limitType model.LimitType, value int64) error {
	s.mu.Lock()
	defer s.mu.Unlock()
	if s.Limits[containerID] == nil {
		s.Limits[containerID] = make(map[model.LimitType]int64)
	}
	s.Limits[containerID][limitType] = value
	return nil
}
testutil.MockStore.GetLimit method · go · L82-L89 (8 LOC)
internal/testutil/mocks.go
func (s *MockStore) GetLimit(containerID string, limitType model.LimitType) (int64, error) {
	s.mu.Lock()
	defer s.mu.Unlock()
	if m, ok := s.Limits[containerID]; ok {
		return m[limitType], nil
	}
	return 0, nil
}
testutil.MockStore.GetAllLimits method · go · L91-L101 (11 LOC)
internal/testutil/mocks.go
func (s *MockStore) GetAllLimits(containerID string) (map[model.LimitType]int64, error) {
	s.mu.Lock()
	defer s.mu.Unlock()
	result := make(map[model.LimitType]int64)
	if m, ok := s.Limits[containerID]; ok {
		for k, v := range m {
			result[k] = v
		}
	}
	return result, nil
}
testutil.MockStore.SetUsage method · go · L103-L111 (9 LOC)
internal/testutil/mocks.go
func (s *MockStore) SetUsage(containerID string, limitType model.LimitType, value int64) error {
	s.mu.Lock()
	defer s.mu.Unlock()
	if s.Usages[containerID] == nil {
		s.Usages[containerID] = make(map[model.LimitType]int64)
	}
	s.Usages[containerID][limitType] = value
	return nil
}
testutil.MockStore.GetUsage method · go · L113-L120 (8 LOC)
internal/testutil/mocks.go
func (s *MockStore) GetUsage(containerID string, limitType model.LimitType) (int64, error) {
	s.mu.Lock()
	defer s.mu.Unlock()
	if m, ok := s.Usages[containerID]; ok {
		return m[limitType], nil
	}
	return 0, nil
}
testutil.MockStore.GetAllUsage method · go · L122-L132 (11 LOC)
internal/testutil/mocks.go
func (s *MockStore) GetAllUsage(containerID string) (map[model.LimitType]int64, error) {
	s.mu.Lock()
	defer s.mu.Unlock()
	result := make(map[model.LimitType]int64)
	if m, ok := s.Usages[containerID]; ok {
		for k, v := range m {
			result[k] = v
		}
	}
	return result, nil
}
testutil.MockStore.AddUsage method · go · L134-L142 (9 LOC)
internal/testutil/mocks.go
func (s *MockStore) AddUsage(containerID string, limitType model.LimitType, delta int64) error {
	s.mu.Lock()
	defer s.mu.Unlock()
	if s.Usages[containerID] == nil {
		s.Usages[containerID] = make(map[model.LimitType]int64)
	}
	s.Usages[containerID][limitType] += delta
	return nil
}
testutil.MockStore.CopyLimits method · go · L144-L157 (14 LOC)
internal/testutil/mocks.go
func (s *MockStore) CopyLimits(fromID, toID string) error {
	s.mu.Lock()
	defer s.mu.Unlock()
	src := s.Limits[fromID]
	if src == nil {
		return nil
	}
	dst := make(map[model.LimitType]int64)
	for k, v := range src {
		dst[k] = v
	}
	s.Limits[toID] = dst
	return nil
}
Open data scored by Repobility · https://repobility.com
testutil.MockStore.ResolveContainerID method · go · L159-L173 (15 LOC)
internal/testutil/mocks.go
func (s *MockStore) ResolveContainerID(query string) (string, error) {
	s.mu.Lock()
	defer s.mu.Unlock()
	// Exact ID match
	if _, ok := s.Containers[query]; ok {
		return query, nil
	}
	// Name match
	for id, c := range s.Containers {
		if c.Name == query {
			return id, nil
		}
	}
	return "", fmt.Errorf("container %q not found", query)
}
testutil.MockDocker.AddContainer method · go · L202-L210 (9 LOC)
internal/testutil/mocks.go
func (d *MockDocker) AddContainer(id string, name string, running bool) {
	d.mu.Lock()
	defer d.mu.Unlock()
	d.Containers[id] = &MockContainerState{
		Running:  running,
		Networks: []string{"bridge"},
		Name:     name,
	}
}
testutil.MockDocker.InspectContainer method · go · L212-L229 (18 LOC)
internal/testutil/mocks.go
func (d *MockDocker) InspectContainer(ctx context.Context, id string) (types.ContainerJSON, error) {
	d.mu.Lock()
	defer d.mu.Unlock()
	state, ok := d.Containers[id]
	if !ok {
		return types.ContainerJSON{}, fmt.Errorf("container %s not found", id)
	}
	return types.ContainerJSON{
		ContainerJSONBase: &types.ContainerJSONBase{
			ID:   id,
			Name: "/" + state.Name,
			State: &types.ContainerState{
				Running: state.Running,
				Paused:  state.Paused,
			},
		},
	}, nil
}
‹ prevpage 2 / 3next ›