60 Semaphore API und CLI

60.1 Überblick über die API

60.1.1 REST-Schnittstelle von Semaphore

Semaphore bietet eine vollständige REST-API, die alle Funktionen der Web-Oberfläche programmatisch zugänglich macht. Die API ermöglicht die Integration von Semaphore in bestehende Automatisierungsworkflows und externe Systeme.

60.1.1.1 API-Eigenschaften

Grundlegende Charakteristika:

60.1.1.2 API-Basis-URL

URL-Struktur:

https://semaphore.company.com/api/v1/

Standard-Ports:

60.1.2 Authentifizierung mit API-Token

60.1.2.1 Token-basierte Authentifizierung

Authentication Header:

Authorization: Bearer YOUR_API_TOKEN_HERE

60.1.2.2 API-Token erstellen

Web-Interface-Weg:

  1. Login in Semaphore Web-UI
  2. Navigation zu User Profile → API Tokens
  3. Create New Token klicken
  4. Token-Name und Berechtigung definieren
  5. Token kopieren und sicher speichern

Token-Eigenschaften:

{
  "id": 42,
  "name": "CI/CD Integration Token",
  "user_id": 1,
  "created": "2024-08-18T10:30:00Z",
  "expires_at": "2024-11-18T10:30:00Z",
  "permissions": ["project:read", "project:execute"]
}

60.1.2.3 Token-Sicherheit

Best Practices:

Umgebungsvariable setzen:

export SEMAPHORE_API_TOKEN="eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."

60.1.3 JSON als Ein- und Ausgabeformat

60.1.3.1 Request-Format

JSON-Request-Beispiel:

{
  "template_id": 5,
  "inventory_id": 2,
  "environment": {
    "deployment_version": "v1.2.3",
    "target_environment": "production"
  }
}

60.1.3.2 Response-Format

Erfolgreiche Antwort:

{
  "id": 1234,
  "template_id": 5,
  "inventory_id": 2,
  "status": "running",
  "start": "2024-08-18T14:30:00Z",
  "created": "2024-08-18T14:29:45Z",
  "user_id": 1
}

Fehler-Response:

{
  "error": "template not found",
  "message": "Template with ID 999 does not exist",
  "code": 404
}

60.2 Typische Endpoints

60.2.1 Jobs starten

60.2.1.1 POST /api/project/:id/tasks

Job-Erstellung:

POST /api/project/1/tasks HTTP/1.1
Host: semaphore.company.com
Authorization: Bearer YOUR_API_TOKEN
Content-Type: application/json

{
  "template_id": 5,
  "inventory_id": 2,
  "environment": {
    "version": "v1.2.3",
    "environment": "production",
    "notify_team": "true"
  }
}

Response bei Erfolg:

{
  "id": 1234,
  "template_id": 5,
  "inventory_id": 2,
  "repository_id": 1,
  "environment": {
    "version": "v1.2.3",
    "environment": "production",
    "notify_team": "true"
  },
  "status": "waiting",
  "created": "2024-08-18T14:30:00Z",
  "start": null,
  "end": null,
  "user_id": 1
}

60.2.1.2 curl-Beispiel

Praktischer Job-Start:

curl -X POST \
  https://semaphore.company.com/api/project/1/tasks \
  -H "Authorization: Bearer $SEMAPHORE_API_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "template_id": 5,
    "inventory_id": 2,
    "environment": {
      "app_version": "v2.1.0",
      "deployment_env": "staging"
    }
  }'

60.2.2 Job-Status abfragen

60.2.2.1 GET /api/project/:id/tasks/:task_id

Status-Abfrage:

GET /api/project/1/tasks/1234 HTTP/1.1
Host: semaphore.company.com
Authorization: Bearer YOUR_API_TOKEN

Response-Beispiel:

{
  "id": 1234,
  "template_id": 5,
  "template": {
    "id": 5,
    "name": "Web Application Deployment",
    "playbook": "deploy-webapp.yml"
  },
  "inventory_id": 2,
  "status": "success",
  "created": "2024-08-18T14:30:00Z",
  "start": "2024-08-18T14:30:15Z",
  "end": "2024-08-18T14:42:30Z",
  "user_id": 1,
  "user": {
    "id": 1,
    "name": "deploy-user",
    "email": "deploy@company.com"
  },
  "environment": {
    "app_version": "v2.1.0",
    "deployment_env": "staging"
  }
}

60.2.2.2 Status-Werte

Mögliche Job-Status:

60.2.2.3 curl-Beispiel für Status-Abfrage

curl -X GET \
  https://semaphore.company.com/api/project/1/tasks/1234 \
  -H "Authorization: Bearer $SEMAPHORE_API_TOKEN"

60.2.3 Job-Logs abrufen

60.2.3.1 GET /api/project/:id/tasks/:task_id/output

Log-Abruf:

curl -X GET \
  https://semaphore.company.com/api/project/1/tasks/1234/output \
  -H "Authorization: Bearer $SEMAPHORE_API_TOKEN"

Log-Response-Format:

{
  "task_id": 1234,
  "time": "2024-08-18T14:30:15Z",
  "output": "PLAY [Deploy Web Application] ***************************************************\n\nTASK [Gathering Facts] *********************************************************\nok: [web01.company.com]\nok: [web02.company.com]\n\nTASK [Update application] ******************************************************\nchanged: [web01.company.com]\nchanged: [web02.company.com]\n\nPLAY RECAP *********************************************************************\nweb01.company.com          : ok=12   changed=3    unreachable=0    failed=0\nweb02.company.com          : ok=12   changed=3    unreachable=0    failed=0"
}

60.2.4 Projekte auflisten

60.2.4.1 GET /api/projects

Projekt-Liste abrufen:

curl -X GET \
  https://semaphore.company.com/api/projects \
  -H "Authorization: Bearer $SEMAPHORE_API_TOKEN"

Response:

[
  {
    "id": 1,
    "name": "Web Application",
    "created": "2024-01-15T10:00:00Z",
    "alert": true,
    "alert_chat": "#deployments",
    "max_parallel_tasks": 3
  },
  {
    "id": 2,
    "name": "Infrastructure Management",
    "created": "2024-02-01T09:30:00Z",
    "alert": false,
    "max_parallel_tasks": 1
  }
]

60.2.5 Templates auflisten

60.2.5.1 GET /api/project/:id/templates

Template-Liste für Projekt:

curl -X GET \
  https://semaphore.company.com/api/project/1/templates \
  -H "Authorization: Bearer $SEMAPHORE_API_TOKEN"

Response:

[
  {
    "id": 5,
    "name": "Deploy Web Application",
    "playbook": "deploy-webapp.yml",
    "inventory_id": 2,
    "repository_id": 1,
    "environment": {
      "app_name": "webapp",
      "default_version": "latest"
    },
    "allow_override_args_in_task": true
  },
  {
    "id": 6,
    "name": "Database Backup",
    "playbook": "backup-database.yml",
    "inventory_id": 3,
    "repository_id": 1,
    "environment": {
      "backup_location": "/backups"
    }
  }
]

60.2.6 Inventories auflisten

60.2.6.1 GET /api/project/:id/inventory

Inventory-Liste:

curl -X GET \
  https://semaphore.company.com/api/project/1/inventory \
  -H "Authorization: Bearer $SEMAPHORE_API_TOKEN"

Response:

[
  {
    "id": 2,
    "name": "Production Web Servers",
    "type": "static",
    "inventory": "web01.company.com\nweb02.company.com\n\n[webservers]\nweb01.company.com\nweb02.company.com",
    "ssh_key_id": 1
  },
  {
    "id": 3,
    "name": "Database Servers",
    "type": "static",
    "inventory": "[databases]\ndb01.company.com\ndb02.company.com",
    "ssh_key_id": 2
  }
]

60.3 CLI-Befehle

60.3.1 Installation und Setup

60.3.1.1 CLI-Installation

Installation per Download:

# Download der aktuellen Version
wget https://github.com/ansible-semaphore/semaphore/releases/latest/download/semaphore_linux_amd64

# Ausführbar machen
chmod +x semaphore_linux_amd64

# In PATH verschieben
sudo mv semaphore_linux_amd64 /usr/local/bin/semaphore

Installation per Package Manager:

# Ubuntu/Debian
sudo apt update && sudo apt install semaphore

# CentOS/RHEL
sudo yum install semaphore

60.3.1.2 CLI-Konfiguration

Grundkonfiguration:

# API-Endpoint konfigurieren
semaphore config set api-url https://semaphore.company.com/api

# API-Token setzen
semaphore config set token YOUR_API_TOKEN

# Konfiguration anzeigen
semaphore config list

Konfigurationsdatei:

# ~/.semaphore/config.yml
api_url: "https://semaphore.company.com/api"
token: "YOUR_API_TOKEN"
default_project: 1
output_format: "json"
timeout: 300

60.3.2 Typische CLI-Szenarien

60.3.2.1 Jobs starten

Template-basierter Job-Start:

# Job mit Template-ID starten
semaphore task start --project 1 --template 5

# Job mit Extra-Variablen
semaphore task start --project 1 --template 5 \
  --var app_version=v2.1.0 \
  --var environment=production

# Job mit JSON-Variablen
semaphore task start --project 1 --template 5 \
  --environment '{"version":"v2.1.0","notify":"true"}'

60.3.2.2 Job-Status überwachen

Status-Abfrage:

# Aktueller Job-Status
semaphore task status --project 1 --task 1234

# Job-Status mit Details
semaphore task show --project 1 --task 1234

# Alle laufenden Jobs
semaphore task list --project 1 --status running

Status-Monitoring mit Watch:

# Kontinuierliche Status-Überwachung
watch -n 5 'semaphore task status --project 1 --task 1234'

# Job bis Completion verfolgen
semaphore task wait --project 1 --task 1234

60.3.2.3 Logs abrufen

Log-Ausgabe:

# Vollständige Logs anzeigen
semaphore task logs --project 1 --task 1234

# Live-Logs verfolgen
semaphore task logs --project 1 --task 1234 --follow

# Logs in Datei speichern
semaphore task logs --project 1 --task 1234 > deployment.log

60.3.2.4 Projekte verwalten

Projekt-Operationen:

# Alle Projekte auflisten
semaphore project list

# Projekt-Details anzeigen
semaphore project show --id 1

# Templates eines Projekts
semaphore template list --project 1

# Inventories anzeigen
semaphore inventory list --project 1

60.3.3 CLI-Flags und Parameter

60.3.3.1 Globale Flags

Allgemeine Parameter:

# Output-Format festlegen
semaphore task list --project 1 --output json
semaphore task list --project 1 --output table
semaphore task list --project 1 --output yaml

# Verbose-Modus
semaphore task start --project 1 --template 5 --verbose

# Timeout setzen
semaphore task wait --project 1 --task 1234 --timeout 3600

60.3.3.2 Task-spezifische Flags

Job-Steuerung:

# Dry-run-Modus
semaphore task start --project 1 --template 5 --check

# Debug-Modus aktivieren
semaphore task start --project 1 --template 5 --debug

# Parallele Ausführung begrenzen
semaphore task start --project 1 --template 5 --limit "web01,web02"

# Tags verwenden
semaphore task start --project 1 --template 5 --tags "deploy,restart"

60.3.4 CLI-Scripting

60.3.4.1 Bash-Integration

Erfolgs-/Fehlerbehandlung:

#!/bin/bash

# Job starten und Task-ID erfassen
TASK_ID=$(semaphore task start --project 1 --template 5 --output json | jq -r '.id')

if [ -z "$TASK_ID" ]; then
    echo "Error: Failed to start job"
    exit 1
fi

echo "Started job with ID: $TASK_ID"

# Auf Job-Completion warten
semaphore task wait --project 1 --task $TASK_ID

# Exit-Code basierend auf Job-Status
STATUS=$(semaphore task status --project 1 --task $TASK_ID --output json | jq -r '.status')

case $STATUS in
    "success")
        echo "Deployment successful"
        exit 0
        ;;
    "error")
        echo "Deployment failed"
        semaphore task logs --project 1 --task $TASK_ID
        exit 1
        ;;
    *)
        echo "Unexpected status: $STATUS"
        exit 2
        ;;
esac

60.4 Integration in externe CI/CD-Pipelines

60.4.1 GitLab CI Integration

60.4.1.1 .gitlab-ci.yml Konfiguration

GitLab Pipeline mit Semaphore:

# .gitlab-ci.yml
stages:
  - build
  - test
  - deploy

variables:
  SEMAPHORE_API_URL: "https://semaphore.company.com/api"
  SEMAPHORE_PROJECT_ID: "1"

build:
  stage: build
  script:
    - echo "Building application..."
    - docker build -t myapp:$CI_COMMIT_SHA .
  artifacts:
    reports:
      dotenv: build.env

test:
  stage: test
  script:
    - echo "Running tests..."
    - npm test

deploy_staging:
  stage: deploy
  only:
    - develop
  script:
    - |
      # Deployment via Semaphore API
      TASK_ID=$(curl -s -X POST \
        "$SEMAPHORE_API_URL/project/$SEMAPHORE_PROJECT_ID/tasks" \
        -H "Authorization: Bearer $SEMAPHORE_API_TOKEN" \
        -H "Content-Type: application/json" \
        -d "{
          \"template_id\": 5,
          \"inventory_id\": 2,
          \"environment\": {
            \"app_version\": \"$CI_COMMIT_SHA\",
            \"environment\": \"staging\",
            \"gitlab_job_id\": \"$CI_JOB_ID\"
          }
        }" | jq -r '.id')
      
      echo "Started Semaphore job: $TASK_ID"
      
      # Warten auf Job-Completion
      while true; do
        STATUS=$(curl -s -H "Authorization: Bearer $SEMAPHORE_API_TOKEN" \
          "$SEMAPHORE_API_URL/project/$SEMAPHORE_PROJECT_ID/tasks/$TASK_ID" \
          | jq -r '.status')
        
        case $STATUS in
          "success")
            echo "Deployment successful"
            break
            ;;
          "error")
            echo "Deployment failed"
            exit 1
            ;;
          "running"|"waiting")
            echo "Job status: $STATUS, waiting..."
            sleep 30
            ;;
          *)
            echo "Unknown status: $STATUS"
            exit 1
            ;;
        esac
      done

deploy_production:
  stage: deploy
  only:
    - main
  when: manual
  script:
    - |
      TASK_ID=$(curl -s -X POST \
        "$SEMAPHORE_API_URL/project/$SEMAPHORE_PROJECT_ID/tasks" \
        -H "Authorization: Bearer $SEMAPHORE_API_TOKEN" \
        -H "Content-Type: application/json" \
        -d "{
          \"template_id\": 6,
          \"inventory_id\": 3,
          \"environment\": {
            \"app_version\": \"$CI_COMMIT_SHA\",
            \"environment\": \"production\"
          }
        }" | jq -r '.id')
      
      echo "Production deployment job: $TASK_ID"

60.4.2 Jenkins Integration

60.4.2.1 Jenkins Pipeline Script

Jenkinsfile mit Semaphore:

pipeline {
    agent any
    
    environment {
        SEMAPHORE_API_URL = 'https://semaphore.company.com/api'
        SEMAPHORE_PROJECT_ID = '1'
        SEMAPHORE_API_TOKEN = credentials('semaphore-api-token')
    }
    
    stages {
        stage('Build') {
            steps {
                sh 'echo "Building application..."'
                sh 'docker build -t myapp:${BUILD_NUMBER} .'
            }
        }
        
        stage('Test') {
            steps {
                sh 'echo "Running tests..."'
                sh 'npm test'
            }
        }
        
        stage('Deploy to Staging') {
            when { branch 'develop' }
            steps {
                script {
                    def taskId = sh(
                        script: """
                            curl -s -X POST \
                              "${SEMAPHORE_API_URL}/project/${SEMAPHORE_PROJECT_ID}/tasks" \
                              -H "Authorization: Bearer ${SEMAPHORE_API_TOKEN}" \
                              -H "Content-Type: application/json" \
                              -d '{
                                "template_id": 5,
                                "inventory_id": 2,
                                "environment": {
                                  "app_version": "${BUILD_NUMBER}",
                                  "environment": "staging",
                                  "jenkins_build": "${BUILD_NUMBER}"
                                }
                              }' | jq -r '.id'
                        """,
                        returnStdout: true
                    ).trim()
                    
                    echo "Started Semaphore job: ${taskId}"
                    
                    // Warten auf Job-Completion
                    timeout(time: 30, unit: 'MINUTES') {
                        waitUntil {
                            script {
                                def status = sh(
                                    script: """
                                        curl -s -H "Authorization: Bearer ${SEMAPHORE_API_TOKEN}" \
                                          "${SEMAPHORE_API_URL}/project/${SEMAPHORE_PROJECT_ID}/tasks/${taskId}" \
                                          | jq -r '.status'
                                    """,
                                    returnStdout: true
                                ).trim()
                                
                                if (status == 'success') {
                                    return true
                                } else if (status == 'error') {
                                    error("Semaphore deployment failed")
                                } else {
                                    echo "Job status: ${status}, waiting..."
                                    sleep(30)
                                    return false
                                }
                            }
                        }
                    }
                }
            }
        }
        
        stage('Deploy to Production') {
            when { branch 'main' }
            steps {
                input message: 'Deploy to production?', ok: 'Deploy'
                script {
                    // Production deployment logic
                    echo "Deploying to production..."
                }
            }
        }
    }
    
    post {
        failure {
            echo 'Pipeline failed!'
        }
        success {
            echo 'Pipeline succeeded!'
        }
    }
}

60.4.3 GitHub Actions Integration

60.4.3.1 GitHub Workflow

GitHub Actions Workflow:

# .github/workflows/deploy.yml
name: Deploy with Semaphore

on:
  push:
    branches: [main, develop]
  pull_request:
    branches: [main]

env:
  SEMAPHORE_API_URL: "https://semaphore.company.com/api"
  SEMAPHORE_PROJECT_ID: "1"

jobs:
  build:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      
      - name: Build application
        run: |
          echo "Building application..."
          docker build -t myapp:${{ github.sha }} .

  deploy-staging:
    needs: build
    if: github.ref == 'refs/heads/develop'
    runs-on: ubuntu-latest
    steps:
      - name: Deploy to staging via Semaphore
        env:
          SEMAPHORE_API_TOKEN: ${{ secrets.SEMAPHORE_API_TOKEN }}
        run: |
          TASK_ID=$(curl -s -X POST \
            "$SEMAPHORE_API_URL/project/$SEMAPHORE_PROJECT_ID/tasks" \
            -H "Authorization: Bearer $SEMAPHORE_API_TOKEN" \
            -H "Content-Type: application/json" \
            -d "{
              \"template_id\": 5,
              \"inventory_id\": 2,
              \"environment\": {
                \"app_version\": \"${{ github.sha }}\",
                \"environment\": \"staging\",
                \"github_run_id\": \"${{ github.run_id }}\"
              }
            }" | jq -r '.id')
          
          echo "Started Semaphore job: $TASK_ID"
          echo "TASK_ID=$TASK_ID" >> $GITHUB_ENV
          
      - name: Wait for deployment completion
        env:
          SEMAPHORE_API_TOKEN: ${{ secrets.SEMAPHORE_API_TOKEN }}
        timeout-minutes: 30
        run: |
          while true; do
            STATUS=$(curl -s -H "Authorization: Bearer $SEMAPHORE_API_TOKEN" \
              "$SEMAPHORE_API_URL/project/$SEMAPHORE_PROJECT_ID/tasks/$TASK_ID" \
              | jq -r '.status')
            
            case $STATUS in
              "success")
                echo "✅ Deployment successful"
                exit 0
                ;;
              "error")
                echo "❌ Deployment failed"
                curl -s -H "Authorization: Bearer $SEMAPHORE_API_TOKEN" \
                  "$SEMAPHORE_API_URL/project/$SEMAPHORE_PROJECT_ID/tasks/$TASK_ID/output"
                exit 1
                ;;
              "running"|"waiting")
                echo "⏳ Job status: $STATUS, waiting..."
                sleep 30
                ;;
              *)
                echo "❓ Unknown status: $STATUS"
                exit 1
                ;;
            esac
          done

  deploy-production:
    needs: build
    if: github.ref == 'refs/heads/main'
    runs-on: ubuntu-latest
    environment: production
    steps:
      - name: Deploy to production
        env:
          SEMAPHORE_API_TOKEN: ${{ secrets.SEMAPHORE_API_TOKEN }}
        run: |
          echo "Deploying to production..."
          # Production deployment logic here

60.5 Übungen

60.5.1 Übung 1: API-Token erstellen und Jobs per curl starten

60.5.1.1 Aufgabenstellung

  1. Erstellen Sie einen API-Token in der Semaphore Web-UI
  2. Starten Sie einen Job über die REST-API mit curl
  3. Überprüfen Sie den Job-Status über die API

60.5.1.2 Durchführung

Schritt 1: API-Token erstellen 1. Login in Semaphore Web-Interface 2. Navigation zu User Profile → API Tokens 3. Create New Token klicken 4. Token-Name: “API-Übung” 5. Token kopieren und als Umgebungsvariable setzen:

export SEMAPHORE_API_TOKEN="IHR_GENERIERTER_TOKEN"

Schritt 2: Verfügbare Projekte anzeigen

curl -X GET \
  https://semaphore.company.com/api/projects \
  -H "Authorization: Bearer $SEMAPHORE_API_TOKEN" \
  | jq '.'

Schritt 3: Templates eines Projekts anzeigen

# Ersetzen Sie PROJECT_ID mit der ID aus Schritt 2
curl -X GET \
  https://semaphore.company.com/api/project/PROJECT_ID/templates \
  -H "Authorization: Bearer $SEMAPHORE_API_TOKEN" \
  | jq '.'

Schritt 4: Job starten

# Ersetzen Sie PROJECT_ID und TEMPLATE_ID mit realen Werten
curl -X POST \
  https://semaphore.company.com/api/project/PROJECT_ID/tasks \
  -H "Authorization: Bearer $SEMAPHORE_API_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "template_id": TEMPLATE_ID,
    "environment": {
      "test_variable": "api_test_value"
    }
  }' | jq '.'

Schritt 5: Job-Status prüfen

# Ersetzen Sie PROJECT_ID und TASK_ID mit den Werten aus Schritt 4
curl -X GET \
  https://semaphore.company.com/api/project/PROJECT_ID/tasks/TASK_ID \
  -H "Authorization: Bearer $SEMAPHORE_API_TOKEN" \
  | jq '.status'

60.5.1.3 Erwartetes Ergebnis

60.5.2 Übung 2: Job-Status über API abfragen und Ergebnis ausgeben

60.5.2.1 Aufgabenstellung

Erstellen Sie ein Bash-Script, das: 1. Einen Job startet 2. Den Status periodisch abfragt 3. Bei Completion das Ergebnis ausgibt 4. Bei Fehler die Logs anzeigt

60.5.2.2 Script-Vorlage

#!/bin/bash

# Konfiguration
PROJECT_ID="1"
TEMPLATE_ID="5"
SEMAPHORE_API_URL="https://semaphore.company.com/api"

# Prüfung der Umgebungsvariablen
if [ -z "$SEMAPHORE_API_TOKEN" ]; then
    echo "Error: SEMAPHORE_API_TOKEN nicht gesetzt"
    exit 1
fi

# Job starten
echo "Starte Job..."
RESPONSE=$(curl -s -X POST \
  "$SEMAPHORE_API_URL/project/$PROJECT_ID/tasks" \
  -H "Authorization: Bearer $SEMAPHORE_API_TOKEN" \
  -H "Content-Type: application/json" \
  -d "{
    \"template_id\": $TEMPLATE_ID,
    \"environment\": {
      \"script_execution\": \"$(date)\"
    }
  }")

# Task-ID extrahieren
TASK_ID=$(echo $RESPONSE | jq -r '.id')

if [ "$TASK_ID" = "null" ] || [ -z "$TASK_ID" ]; then
    echo "Error: Job konnte nicht gestartet werden"
    echo "Response: $RESPONSE"
    exit 1
fi

echo "Job gestartet mit ID: $TASK_ID"

# Status-Monitoring
while true; do
    STATUS_RESPONSE=$(curl -s -H "Authorization: Bearer $SEMAPHORE_API_TOKEN" \
      "$SEMAPHORE_API_URL/project/$PROJECT_ID/tasks/$TASK_ID")
    
    STATUS=$(echo $STATUS_RESPONSE | jq -r '.status')
    
    case $STATUS in
        "waiting")
            echo "⏳ Job wartet in der Queue..."
            ;;
        "running")
            echo "🔄 Job läuft..."
            ;;
        "success")
            echo "✅ Job erfolgreich abgeschlossen!"
            break
            ;;
        "error")
            echo "❌ Job fehlgeschlagen!"
            echo "Hole Logs..."
            curl -s -H "Authorization: Bearer $SEMAPHORE_API_TOKEN" \
              "$SEMAPHORE_API_URL/project/$PROJECT_ID/tasks/$TASK_ID/output" \
              | jq -r '.output'
            exit 1
            ;;
        *)
            echo "❓ Unbekannter Status: $STATUS"
            ;;
    esac
    
    sleep 10
done

echo "Job-Details:"
echo $STATUS_RESPONSE | jq '{id, status, start, end, user}'

60.5.2.3 Durchführung

  1. Script in Datei job_monitor.sh speichern
  2. Ausführbar machen: chmod +x job_monitor.sh
  3. Ausführen: ./job_monitor.sh

60.5.2.4 Erwartetes Ergebnis

60.5.3 Übung 3: Job per CLI starten und Logs abrufen

60.5.3.1 Aufgabenstellung

  1. Installieren Sie die Semaphore CLI
  2. Konfigurieren Sie die CLI für Ihre Semaphore-Instanz
  3. Starten Sie einen Job per CLI
  4. Verfolgen Sie die Logs in Echtzeit

60.5.3.2 Durchführung

Schritt 1: CLI Installation prüfen/installieren

# Prüfen ob CLI installiert ist
semaphore --version

# Falls nicht installiert (Ubuntu/Debian):
sudo apt update && sudo apt install semaphore

Schritt 2: CLI konfigurieren

# Konfiguration erstellen
mkdir -p ~/.semaphore

cat > ~/.semaphore/config.yml << EOF
api_url: "https://semaphore.company.com/api"
token: "$SEMAPHORE_API_TOKEN"
default_project: 1
output_format: "json"
timeout: 300
EOF

Schritt 3: Verfügbare Templates anzeigen

semaphore template list --project 1

Schritt 4: Job starten

# Job mit Template-ID starten
semaphore task start --project 1 --template TEMPLATE_ID \
  --var environment=cli_test \
  --var timestamp="$(date)"

Schritt 5: Job-Status verfolgen

# Task-ID aus Schritt 4 verwenden
semaphore task status --project 1 --task TASK_ID

# Auf Completion warten
semaphore task wait --project 1 --task TASK_ID

Schritt 6: Logs abrufen

# Vollständige Logs anzeigen
semaphore task logs --project 1 --task TASK_ID

# Live-Logs verfolgen (falls Job noch läuft)
semaphore task logs --project 1 --task TASK_ID --follow

60.5.3.3 Erwartetes Ergebnis

60.5.4 Übung 4: Semaphore-Job in GitLab CI-Pipeline einbinden

60.5.4.1 Aufgabenstellung

Erstellen Sie eine GitLab CI-Pipeline, die: 1. Code baut 2. Tests ausführt 3. Bei erfolgreichen Tests ein Deployment via Semaphore triggert 4. Das Deployment-Ergebnis überwacht

60.5.4.2 Durchführung

Schritt 1: GitLab CI Variables setzen

In GitLab: Settings → CI/CD → Variables

SEMAPHORE_API_TOKEN: Ihr API-Token (protected, masked)
SEMAPHORE_API_URL: https://semaphore.company.com/api
SEMAPHORE_PROJECT_ID: 1
SEMAPHORE_TEMPLATE_ID: 5

Schritt 2: .gitlab-ci.yml erstellen

# .gitlab-ci.yml
stages:
  - build
  - test
  - deploy

variables:
  APP_NAME: "test-application"

build_job:
  stage: build
  script:
    - echo "Building $APP_NAME..."
    - echo "Build successful" > build.txt
  artifacts:
    paths:
      - build.txt
    expire_in: 1 hour

test_job:
  stage: test
  script:
    - echo "Running tests for $APP_NAME..."
    - echo "All tests passed"
    # Hier würden echte Tests laufen

deploy_job:
  stage: deploy
  only:
    - main
    - develop
  script:
    - |
      echo "Triggering deployment via Semaphore..."
      
      # Job starten
      RESPONSE=$(curl -s -X POST \
        "$SEMAPHORE_API_URL/project/$SEMAPHORE_PROJECT_ID/tasks" \
        -H "Authorization: Bearer $SEMAPHORE_API_TOKEN" \
        -H "Content-Type: application/json" \
        -d "{
          \"template_id\": $SEMAPHORE_TEMPLATE_ID,
          \"environment\": {
            \"app_name\": \"$APP_NAME\",
            \"app_version\": \"$CI_COMMIT_SHA\",
            \"gitlab_job_id\": \"$CI_JOB_ID\",
            \"gitlab_pipeline_id\": \"$CI_PIPELINE_ID\",
            \"branch\": \"$CI_COMMIT_REF_NAME\"
          }
        }")
      
      TASK_ID=$(echo $RESPONSE | jq -r '.id')
      
      if [ "$TASK_ID" = "null" ]; then
        echo "Error: Failed to start Semaphore job"
        echo "Response: $RESPONSE"
        exit 1
      fi
      
      echo "Semaphore job started with ID: $TASK_ID"
      
      # Auf Completion warten
      TIMEOUT=1800  # 30 Minuten
      ELAPSED=0
      
      while [ $ELAPSED -lt $TIMEOUT ]; do
        STATUS=$(curl -s -H "Authorization: Bearer $SEMAPHORE_API_TOKEN" \
          "$SEMAPHORE_API_URL/project/$SEMAPHORE_PROJECT_ID/tasks/$TASK_ID" \
          | jq -r '.status')
        
        case $STATUS in
          "success")
            echo "✅ Deployment successful!"
            echo "Semaphore job completed successfully"
            exit 0
            ;;
          "error")
            echo "❌ Deployment failed!"
            echo "Fetching logs..."
            curl -s -H "Authorization: Bearer $SEMAPHORE_API_TOKEN" \
              "$SEMAPHORE_API_URL/project/$SEMAPHORE_PROJECT_ID/tasks/$TASK_ID/output" \
              | jq -r '.output' | tail -50
            exit 1
            ;;
          "running"|"waiting")
            echo "⏳ Status: $STATUS (${ELAPSED}s elapsed)"
            sleep 30
            ELAPSED=$((ELAPSED + 30))
            ;;
          *)
            echo "❓ Unknown status: $STATUS"
            sleep 30
            ELAPSED=$((ELAPSED + 30))
            ;;
        esac
      done
      
      echo "❌ Timeout: Deployment took longer than expected"
      exit 1

Schritt 3: Repository committen und Pipeline testen

git add .gitlab-ci.yml
git commit -m "Add Semaphore integration to CI/CD pipeline"
git push origin main

Schritt 4: Pipeline in GitLab beobachten

  1. In GitLab zu CI/CD → Pipelines navigieren
  2. Pipeline-Ausführung beobachten
  3. Deploy-Job-Logs prüfen

60.5.4.3 Erwartetes Ergebnis

60.5.4.4 Zusatzaufgabe: Fehlerbehandlung

Erweitern Sie die Pipeline um:

deploy_job:
  # ... bestehende Konfiguration ...
  after_script:
    - |
      if [ $CI_JOB_STATUS = "failed" ]; then
        echo "Deployment failed, sending notification..."
        # Hier könnte eine Slack-Benachrichtigung o.ä. stehen
      fi
  artifacts:
    when: always
    reports:
      dotenv: deployment.env
    paths:
      - deployment.log

Diese Übungen führen progressiv von einfachen API-Calls zu komplexer CI/CD-Integration und bieten praktische Erfahrung mit allen wichtigen Aspekten der Semaphore-API und CLI.