Version API - Endpoint Wersji Managera
Przegląd
Endpoint /api/v2/version w Dagu API udostępnia aktualną wersję managera odczytaną z pliku .release.txt. Umożliwia to zewnętrznym systemom (np. proxy, dashboard) pobieranie informacji o wersji bez konieczności dostępu do systemu plików.
Konfiguracja
1. GitHub Workflow - Automatyczne Tworzenie .release.txt (Production)
W workflow .github/workflows/build-release.yml automatycznie tworzy plik wersji przy każdym release:
- name: Create version file
run: |
echo "${{ github.event.release.tag_name }}" > .release.txt
echo "Created .release.txt with version: $(cat .release.txt)"Działanie:
- Triggeruje się przy publikacji GitHub release
- Tworzy
.release.txtz tagiem release (np.v1.2.7) - Kopiuje plik do paczki deployment
- Paczka zawiera
.release.txtgotowy do użycia na serwerze
Deployment:
# Po rozpakowaniu paczki na serwerze:
tar -xzf code-generations_manager.tar.gz
cat .release.txt # v1.2.7 (już jest w paczce!)2. Git Hook - Lokalne Development (Optional)
Do lokalnego testowania możesz zainstalować git hook:
#!/bin/bash
cd "$(git rev-parse --show-toplevel)"
VERSION=$(git describe --tags --always 2>/dev/null || echo "dev")
echo "$VERSION" > .release.txtInstalacja (opcjonalna):
cat > .git/hooks/post-commit << 'EOF'
#!/bin/bash
cd "$(git rev-parse --show-toplevel)"
VERSION=$(git describe --tags --always 2>/dev/null || echo "dev")
echo "$VERSION" > .release.txt
EOF
chmod +x .git/hooks/post-commitKiedy używać:
- Lokalny development
- Testowanie Dagu API przed release
UWAGA: Na produkcji używany jest plik z GitHub workflow!
3. Lokalizacja Pliku
Plik .release.txt znajduje się w głównym katalogu managera:
/Users/tkowalski/Projects/code-generations/manager/
├── .release.txt # <-- tutaj
├── dags/
├── docker/
└── tasks/Format zawartości:
v1.2.7Modyfikacja Dagu
1. OpenAPI Spec - Dodanie Endpointu
W pliku api/v2/api.yaml dodano nowy endpoint:
/version:
get:
summary: "Get manager version"
description: "Returns the current manager version from .release.txt file"
operationId: "getManagerVersion"
tags:
- "system"
responses:
"200":
description: "A successful response"
content:
application/json:
schema:
$ref: "#/components/schemas/VersionResponse"
default:
description: "Unexpected error"2. Response Schema
W sekcji components/schemas dodano typ odpowiedzi:
VersionResponse:
type: object
description: "Response object for the manager version endpoint"
properties:
version:
type: string
description: "Current manager version from .release.txt"
required:
- version3. Handler Implementation
Utworzono plik internal/service/frontend/api/v2/version.go:
package api
import (
"context"
"os"
"path/filepath"
"strings"
"github.com/dagu-org/dagu/api/v2"
)
func (a *API) GetManagerVersion(_ context.Context, _ api.GetManagerVersionRequestObject) (api.GetManagerVersionResponseObject, error) {
// Read version from .release.txt in the project root (dags directory parent)
dagsDir := a.config.Paths.DAGsDir
projectRoot := filepath.Dir(dagsDir)
versionFile := filepath.Join(projectRoot, ".release.txt")
data, err := os.ReadFile(versionFile)
if err != nil {
// If file doesn't exist or can't be read, return "unknown"
return &api.GetManagerVersion200JSONResponse{
Version: "unknown",
}, nil
}
version := strings.TrimSpace(string(data))
if version == "" {
version = "unknown"
}
return &api.GetManagerVersion200JSONResponse{
Version: version,
}, nil
}Działanie:
- Odczytuje ścieżkę do katalogu
dags/z konfiguracji Dagu - Wyznacza katalog główny projektu (parent od
dags/) - Czyta
.release.txtz głównego katalogu - Zwraca wersję lub
"unknown"w przypadku błędu
4. Generowanie API Code
Po modyfikacji OpenAPI spec należy wygenerować kod:
cd /tmp/dagu-custom
make apiTo polecenie:
- Waliduje spec OpenAPI
- Generuje interfejsy Go (
api/v2/api.gen.go) - Tworzy typy dla
VersionResponse - Dodaje route
/versiondo routera chi
5. Build Custom Dagu
Build zmodyfikowanego Dagu:
cd /tmp/dagu-custom
make binBinary znajduje się w .local/bin/dagu.
6. Instalacja
Skopiowanie nowego binary do lokalizacji Dagu:
# Backup oryginalnego
cp /Users/tkowalski/.dagu/bin/dagu /Users/tkowalski/.dagu/bin/dagu.backup
# Instalacja nowej wersji
cp /tmp/dagu-custom/.local/bin/dagu /Users/tkowalski/.dagu/bin/dagu
cp /tmp/dagu-custom/.local/bin/dagu /Users/tkowalski/bin/dagu
# Restart Dagu
cd /Users/tkowalski/Projects/code-generations/manager
./manager.sh restartUżycie API
Podstawowe Query
curl http://127.0.0.1:8080/api/v2/versionResponse:
{
"version": "v1.2.7"
}Z jq Parsing
VERSION=$(curl -s http://127.0.0.1:8080/api/v2/version | jq -r '.version')
echo "Manager version: $VERSION"Output:
Manager version: v1.2.7Check Health + Version
# Health check
curl http://127.0.0.1:8080/api/v2/health
# Version check
curl http://127.0.0.1:8080/api/v2/versionZ Timeout
curl --max-time 5 http://127.0.0.1:8080/api/v2/versionIntegracja z Proxy
Konfiguracja Proxy
W config.yml proxy używa istniejącego ustawienia:
codegen_v2:
dagu_api_url: "http://127.0.0.1:8080"Service Layer
Plik internal/service/manager_version.go:
package service
import (
"daily-app/internal/config"
"encoding/json"
"fmt"
"net/http"
"time"
)
type versionResponse struct {
Version string `json:"version"`
}
func GetManagerVersion() (string, error) {
cfg := config.Get()
if cfg == nil || cfg.CodeGenV2.DaguAPIUrl == "" {
return "unknown", nil
}
// Call Dagu API /version endpoint
url := fmt.Sprintf("%s/api/v2/version", cfg.CodeGenV2.DaguAPIUrl)
client := &http.Client{Timeout: 5 * time.Second}
resp, err := client.Get(url)
if err != nil {
return "unknown", err
}
defer resp.Body.Close()
if resp.StatusCode != http.StatusOK {
return "unknown", fmt.Errorf("dagu API returned status %d", resp.StatusCode)
}
var vr versionResponse
if err := json.NewDecoder(resp.Body).Decode(&vr); err != nil {
return "unknown", err
}
return vr.Version, nil
}Handler
W internal/handler/index.go:
func HandleIndex(w http.ResponseWriter, r *http.Request) {
// ... existing code ...
// Get manager version
managerVersion, err := service.GetManagerVersion()
if err != nil {
log.Printf("Error getting manager version: %v", err)
managerVersion = "unknown"
}
index.Dashboard(announcements, managerVersion).Render(r.Context(), w)
}Dashboard Template
W internal/render/index/dashboard.templ:
<!-- Manager Version Card -->
<div class="bg-white dark:bg-gray-800 overflow-hidden shadow-sm rounded-lg border border-gray-200 dark:border-gray-700">
<div class="p-6">
<div class="flex items-center">
<div class="flex-shrink-0">
<svg class="h-8 w-8 text-indigo-600 dark:text-indigo-400" fill="none" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" d="M9.568 3H5.25A2.25 2.25 0 003 5.25v4.318c0 .597.237 1.17.659 1.591l9.581 9.581c.699.699 1.78.872 2.607.33a18.095 18.095 0 005.223-5.223c.542-.827.369-1.908-.33-2.607L11.16 3.66A2.25 2.25 0 009.568 3z" />
<path stroke-linecap="round" stroke-linejoin="round" d="M6 6h.008v.008H6V6z" />
</svg>
</div>
<div class="ml-5 w-0 flex-1">
<dl>
<dt class="text-sm font-medium text-gray-500 dark:text-gray-400 truncate">Manager Version</dt>
<dd class="text-lg font-semibold text-gray-900 dark:text-gray-100">{ managerVersion }</dd>
</dl>
</div>
</div>
<div class="mt-4">
<p class="text-sm text-gray-600 dark:text-gray-400">Current release version</p>
</div>
</div>
</div>Przepływ Danych
┌──────────────┐
│ Git Commit │
└──────┬───────┘
│ post-commit hook
▼
┌──────────────────┐
│ .release.txt │ ◄─── git describe --tags
│ v1.2.7 │
└──────┬───────────┘
│
▼
┌──────────────────────────────┐
│ Dagu API │
│ GET /api/v2/version │
│ - Reads .release.txt │
│ - Returns JSON │
└──────┬───────────────────────┘
│ HTTP GET
▼
┌──────────────────────────────┐
│ Proxy │
│ - Calls Dagu API │
│ - Parses JSON response │
│ - Displays on dashboard │
└──────────────────────────────┘
│
▼
┌──────────────────────────────┐
│ User Dashboard │
│ Box: "Manager Version" │
│ Value: "v1.2.7" │
└──────────────────────────────┘Monitoring
Sprawdzenie Statusu Endpointu
# Check if Dagu is running
curl -s http://127.0.0.1:8080/api/v2/health | jq '.status'
# Check version endpoint
curl -s http://127.0.0.1:8080/api/v2/version | jq '.version'Logi Dagu
# Server logs
tail -f /Users/tkowalski/.dagu/dagu.log
# Grep for version requests
tail -f /Users/tkowalski/.dagu/dagu.log | grep "/version"Sprawdzenie Pliku .release.txt
# Show current version
cat /Users/tkowalski/Projects/code-generations/manager/.release.txt
# Watch for changes
watch -n 5 cat /Users/tkowalski/Projects/code-generations/manager/.release.txtTroubleshooting
Endpoint Zwraca 404
Problem:
curl http://127.0.0.1:8080/api/v2/version
# 404 page not foundPrzyczyny:
- Dagu nie został zrestartowany po instalacji
- Używasz starej wersji Dagu bez custom endpointu
Rozwiązanie:
# Sprawdź wersję Dagu
dagu version
# Powinno być: v1.26.6-YYMMDDHHMMSS
# Restart Dagu
cd /Users/tkowalski/Projects/code-generations/manager
./manager.sh restart
# Test ponownie
curl http://127.0.0.1:8080/api/v2/versionEndpoint Zwraca "unknown"
Problem:
{
"version": "unknown"
}Przyczyny:
- Brak pliku
.release.txt - Plik pusty
- Nieprawidłowa ścieżka do pliku
Rozwiązanie:
# Sprawdź czy plik istnieje
ls -la /Users/tkowalski/Projects/code-generations/manager/.release.txt
# Jeśli nie istnieje, utwórz manualnie
cd /Users/tkowalski/Projects/code-generations/manager
git describe --tags --always > .release.txt
# Sprawdź zawartość
cat .release.txt
# Test API
curl http://127.0.0.1:8080/api/v2/versionGit Hook Nie Działa
Problem: .release.txt nie aktualizuje się przy commitach
Rozwiązanie:
# Sprawdź czy hook istnieje
ls -la .git/hooks/post-commit
# Jeśli nie istnieje, utwórz
cat > .git/hooks/post-commit << 'EOF'
#!/bin/bash
cd "$(git rev-parse --show-toplevel)"
VERSION=$(git describe --tags --always 2>/dev/null || echo "dev")
echo "$VERSION" > .release.txt
git add .release.txt 2>/dev/null || true
EOF
# Nadaj uprawnienia
chmod +x .git/hooks/post-commit
# Test
git commit --allow-empty -m "Test version update"
cat .release.txtProxy Nie Może Połączyć się z Dagu
Problem: Proxy pokazuje "unknown" na dashboardzie
Diagnoza:
# Test z proxy machine
curl http://127.0.0.1:8080/api/v2/version
# Sprawdź logi proxy
grep "manager version" /path/to/proxy/logsRozwiązanie:
# Sprawdź config proxy
cat config.yml | grep dagu_api_url
# Sprawdź czy Dagu nasłuchuje na prawidłowym porcie
lsof -i :8080 | grep dagu
# Sprawdź firewall
# (jeśli proxy i manager są na różnych hostach)Wersjonowanie
Format Wersji
System używa semantic versioning z tagami git:
v1.2.7
└─┼─┼─── Patch version (bug fixes)
│ └──── Minor version (new features)
└────── Major version (breaking changes)Tworzenie Nowej Wersji
# Tag nowej wersji
git tag -a v1.2.8 -m "Release v1.2.8: Add version API endpoint"
# Push taga
git push origin v1.2.8
# Commit (hook automatycznie zaktualizuje .release.txt)
git commit --allow-empty -m "Bump version to v1.2.8"
# Sprawdź
cat .release.txt
# v1.2.8
# Test API
curl http://127.0.0.1:8080/api/v2/version
# {"version":"v1.2.8"}Historia Wersji
# Lista wszystkich wersji
git tag -l | sort -V
# Ostatnie 5 wersji
git tag -l | sort -V | tail -5
# Różnice między wersjami
git log v1.2.7..v1.2.8 --onelineBest Practices
1. Zawsze Taguj Releasy
# Po merge do main
git tag -a v1.2.8 -m "Release v1.2.8"
git push origin v1.2.82. Utrzymuj .release.txt w Sync
# Jeśli hook nie zadziałał, ręcznie:
git describe --tags --always > .release.txt
git add .release.txt
git commit -m "Update version file"3. Monitoruj API
# Dodaj healthcheck dla version endpoint
curl -f http://127.0.0.1:8080/api/v2/version || echo "Version API down!"4. Backup Dagu Binary
# Przed każdą aktualizacją
cp ~/.dagu/bin/dagu ~/.dagu/bin/dagu.backup.$(date +%Y%m%d)Pliki i Lokalizacje
Manager (Git Repository)
/Users/tkowalski/Projects/code-generations/manager/
├── .release.txt # Wersja (lokalna lub z deployment)
├── .git/hooks/post-commit # Git hook (optional, lokalny)
├── .github/workflows/build-release.yml # GitHub workflow (production)
├── dags/ # Dagu DAG workflows
└── .doc/operations/version-api.md # Ta dokumentacjaProduction Deployment
/path/to/production/manager/
├── .release.txt # Z GitHub workflow
├── dags/
├── docker/
├── plugins/
└── workspace/Dagu (Custom Build)
/tmp/dagu-custom/
├── api/v2/api.yaml # OpenAPI spec
├── api/v2/api.gen.go # Generated code
├── internal/service/frontend/api/v2/
│ ├── api.go # API setup
│ └── version.go # Version handler
└── .local/bin/dagu # Built binaryInstalacja
/Users/tkowalski/.dagu/bin/dagu # Dagu binary (aktywny)
/Users/tkowalski/bin/dagu # Dagu binary (symlink)Proxy
/Users/tkowalski/Projects/code-generations/enginering-proxy/
├── config.yml # Konfiguracja (dagu_api_url)
├── internal/service/manager_version.go # Service layer
├── internal/handler/index.go # Handler
└── internal/render/index/dashboard.templ # Template