Feuille de chauffage du port
Aperçu général
Port est une plateforme de développeurs internes (IDP) qui crée un portail de développeurs complet pour la gestion et la visualisation de tout votre catalogue de logiciels. Il fournit une interface unifiée pour les flux de travail des services, de l'infrastructure, des déploiements et des développeurs, tout en permettant des capacités de libre-service et en maintenant des normes de gouvernance et de conformité.
C'est pas vrai. Note: Niveau gratuit disponible pour les petites équipes. Les plans payés commencent à $20/utilisateur/mois pour les fonctionnalités avancées.
Commencer
Configuration du compte
# Sign up process:
# 1. Visit getport.io
# 2. Create account with email or SSO
# 3. Set up your organization
# 4. Configure initial data model
# 5. Connect your first data sources
# Initial configuration:
# - Organization settings
# - User roles and permissions
# - Data model design
# - Integration setup
# - Team onboarding
Conception du modèle de données
{
"identifier": "service",
"title": "Service",
"icon": "Service",
"schema": {
"properties": {
"name": {
"title": "Name",
"type": "string"
},
"description": {
"title": "Description",
"type": "string"
},
"owner": {
"title": "Owner",
"type": "string",
"format": "team"
},
"language": {
"title": "Language",
"type": "string",
"enum": ["Python", "JavaScript", "Java", "Go", "C#"]
},
"lifecycle": {
"title": "Lifecycle",
"type": "string",
"enum": ["Production", "Staging", "Development", "Deprecated"]
},
"tier": {
"title": "Tier",
"type": "string",
"enum": ["Mission Critical", "Customer Facing", "Internal", "Experimental"]
}
},
"required": ["name", "owner", "lifecycle"]
}
}
```_
### Création du plan directeur
```json
{
"identifier": "microservice",
"title": "Microservice",
"icon": "Microservice",
"schema": {
"properties": {
"name": {
"title": "Service Name",
"type": "string"
},
"repository": {
"title": "Repository",
"type": "string",
"format": "url"
},
"health_status": {
"title": "Health Status",
"type": "string",
"enum": ["Healthy", "Warning", "Critical", "Unknown"]
},
"deployment_status": {
"title": "Deployment Status",
"type": "string",
"enum": ["Deployed", "Deploying", "Failed", "Not Deployed"]
},
"cpu_usage": {
"title": "CPU Usage (%)",
"type": "number"
},
"memory_usage": {
"title": "Memory Usage (%)",
"type": "number"
},
"last_deployment": {
"title": "Last Deployment",
"type": "string",
"format": "date-time"
}
}
},
"relations": {
"team": {
"title": "Team",
"target": "team",
"required": true,
"many": false
},
"domain": {
"title": "Domain",
"target": "domain",
"required": false,
"many": false
}
}
}
```_
## Ingestion des données
### Intégration de l'API REST
```python
import requests
import json
# Port API configuration
PORT_API_URL = "https://api.getport.io/v1"
PORT_CLIENT_ID = "your-client-id"
PORT_CLIENT_SECRET = "your-client-secret"
# Get access token
def get_access_token():
response = requests.post(
f"{PORT_API_URL}/auth/access_token",
json={
"clientId": PORT_CLIENT_ID,
"clientSecret": PORT_CLIENT_SECRET
}
)
return response.json()["accessToken"]
# Create or update entity
def upsert_entity(blueprint_id, entity_data):
token = get_access_token()
headers = {
"Authorization": f"Bearer {token}",
"Content-Type": "application/json"
}
response = requests.post(
f"{PORT_API_URL}/blueprints/{blueprint_id}/entities",
headers=headers,
json=entity_data
)
return response.json()
# Example: Create service entity
service_data = {
"identifier": "user-service",
"title": "User Service",
"properties": {
"name": "User Service",
"description": "Handles user authentication and management",
"owner": "backend-team",
"language": "Python",
"lifecycle": "Production",
"tier": "Customer Facing"
},
"relations": {
"team": "backend-team",
"domain": "authentication"
}
}
result = upsert_entity("service", service_data)
print(json.dumps(result, indent=2))
Intégration de Webhook
from flask import Flask, request, jsonify
import requests
app = Flask(__name__)
@app.route('/port-webhook', methods=['POST'])
def handle_port_webhook():
"""Handle incoming webhooks from Port"""
data = request.json
# Process different event types
if data.get('eventType') == 'ENTITY_CREATED':
handle_entity_created(data)
elif data.get('eventType') == 'ENTITY_UPDATED':
handle_entity_updated(data)
elif data.get('eventType') == 'ENTITY_DELETED':
handle_entity_deleted(data)
return jsonify({"status": "success"})
def handle_entity_created(data):
"""Handle entity creation events"""
entity = data.get('entity', {})
blueprint = data.get('blueprint', {})
print(f"New {blueprint.get('identifier')} created: {entity.get('identifier')}")
# Trigger downstream processes
if blueprint.get('identifier') == 'service':
setup_monitoring(entity)
create_alerts(entity)
def setup_monitoring(entity):
"""Set up monitoring for new service"""
service_name = entity.get('identifier')
# Configure monitoring tools
print(f"Setting up monitoring for {service_name}")
def create_alerts(entity):
"""Create alerts for new service"""
service_name = entity.get('identifier')
# Configure alerting
print(f"Creating alerts for {service_name}")
if __name__ == '__main__':
app.run(host='0.0.0.0', port=5000)
Intégration GitHub
# .github/workflows/port-sync.yml
name: Sync with Port
on:
push:
branches: [main]
pull_request:
branches: [main]
jobs:
sync-to-port:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Extract service metadata
id: metadata
run: |
# Extract metadata from repository
SERVICE_NAME=$(basename $GITHUB_REPOSITORY)
LANGUAGE=$(find . -name "*.py" -o -name "*.js" -o -name "*.java" | head -1 | sed 's/.*\.//')
echo "service_name=$SERVICE_NAME" >> $GITHUB_OUTPUT
echo "language=$LANGUAGE" >> $GITHUB_OUTPUT
- name: Update Port entity
uses: port-labs/port-github-action@v1
with:
clientId: ${{ secrets.PORT_CLIENT_ID }}
clientSecret: ${{ secrets.PORT_CLIENT_SECRET }}
operation: UPSERT
identifier: ${{ steps.metadata.outputs.service_name }}
blueprint: service
properties: |
{
"name": "${{ steps.metadata.outputs.service_name }}",
"repository": "${{ github.repository }}",
"language": "${{ steps.metadata.outputs.language }}",
"lifecycle": "Production",
"last_commit": "${{ github.sha }}"
}
Kubernetes Intégration
# Port Kubernetes exporter
apiVersion: apps/v1
kind: Deployment
metadata:
name: port-k8s-exporter
namespace: port-k8s-exporter
spec:
replicas: 1
selector:
matchLabels:
app: port-k8s-exporter
template:
metadata:
labels:
app: port-k8s-exporter
spec:
serviceAccountName: port-k8s-exporter
containers:
- name: port-k8s-exporter
image: ghcr.io/port-labs/port-k8s-exporter:latest
env:
- name: PORT_CLIENT_ID
valueFrom:
secretKeyRef:
name: port-credentials
key: clientId
- name: PORT_CLIENT_SECRET
valueFrom:
secretKeyRef:
name: port-credentials
key: clientSecret
- name: CONFIG_YAML
value: |
resources:
- kind: v1/pods
selector:
query: .metadata.namespace | startswith("kube") | not
port:
entity:
mappings:
- identifier: .metadata.name + "-" + .metadata.namespace
title: .metadata.name
blueprint: '"k8s-pod"'
properties:
namespace: .metadata.namespace
status: .status.phase
node: .spec.nodeName
created: .metadata.creationTimestamp
- kind: apps/v1/deployments
port:
entity:
mappings:
- identifier: .metadata.name + "-" + .metadata.namespace
title: .metadata.name
blueprint: '"k8s-deployment"'
properties:
namespace: .metadata.namespace
replicas: .spec.replicas
available_replicas: .status.availableReplicas
strategy: .spec.strategy.type
Actions en libre-service
Définition
{
"identifier": "deploy_service",
"title": "Deploy Service",
"icon": "Deploy",
"description": "Deploy a service to the specified environment",
"trigger": {
"type": "self-service",
"operation": "CREATE",
"userInputs": {
"properties": {
"environment": {
"title": "Environment",
"type": "string",
"enum": ["development", "staging", "production"],
"default": "development"
},
"version": {
"title": "Version",
"type": "string",
"description": "Docker image tag to deploy"
},
"replicas": {
"title": "Replicas",
"type": "number",
"default": 1,
"minimum": 1,
"maximum": 10
},
"cpu_limit": {
"title": "CPU Limit",
"type": "string",
"default": "500m",
"enum": ["100m", "250m", "500m", "1000m"]
},
"memory_limit": {
"title": "Memory Limit",
"type": "string",
"default": "512Mi",
"enum": ["256Mi", "512Mi", "1Gi", "2Gi"]
}
},
"required": ["environment", "version"]
},
"blueprintIdentifier": "service"
},
"invocationMethod": {
"type": "WEBHOOK",
"url": "https://api.company.com/deploy",
"method": "POST",
"headers": {
"Authorization": "Bearer {{ .secrets.DEPLOY_TOKEN }}"
},
"body": {
"service": "{{ .entity.identifier }}",
"environment": "{{ .inputs.environment }}",
"version": "{{ .inputs.version }}",
"replicas": "{{ .inputs.replicas }}",
"resources": {
"cpu": "{{ .inputs.cpu_limit }}",
"memory": "{{ .inputs.memory_limit }}"
}
}
}
}
Intégration des actions GitHub
{
"identifier": "create_repository",
"title": "Create Repository",
"icon": "Github",
"description": "Create a new GitHub repository with template",
"trigger": {
"type": "self-service",
"operation": "CREATE",
"userInputs": {
"properties": {
"name": {
"title": "Repository Name",
"type": "string",
"pattern": "^[a-z0-9-]+$"
},
"description": {
"title": "Description",
"type": "string"
},
"template": {
"title": "Template",
"type": "string",
"enum": ["microservice", "frontend", "library", "documentation"]
},
"team": {
"title": "Owning Team",
"type": "string",
"format": "team"
},
"visibility": {
"title": "Visibility",
"type": "string",
"enum": ["private", "internal", "public"],
"default": "private"
}
},
"required": ["name", "template", "team"]
}
},
"invocationMethod": {
"type": "GITHUB",
"org": "your-org",
"repo": "platform-workflows",
"workflow": "create-repository.yml",
"workflowInputs": {
"repository_name": "{{ .inputs.name }}",
"description": "{{ .inputs.description }}",
"template": "{{ .inputs.template }}",
"team": "{{ .inputs.team }}",
"visibility": "{{ .inputs.visibility }}"
}
}
}
Intégration Terraform
{
"identifier": "provision_infrastructure",
"title": "Provision Infrastructure",
"icon": "Terraform",
"description": "Provision cloud infrastructure using Terraform",
"trigger": {
"type": "self-service",
"operation": "CREATE",
"userInputs": {
"properties": {
"environment": {
"title": "Environment",
"type": "string",
"enum": ["dev", "staging", "prod"]
},
"instance_type": {
"title": "Instance Type",
"type": "string",
"enum": ["t3.micro", "t3.small", "t3.medium", "t3.large"]
},
"region": {
"title": "AWS Region",
"type": "string",
"enum": ["us-east-1", "us-west-2", "eu-west-1"]
},
"auto_scaling": {
"title": "Enable Auto Scaling",
"type": "boolean",
"default": false
}
},
"required": ["environment", "instance_type", "region"]
}
},
"invocationMethod": {
"type": "WEBHOOK",
"url": "https://terraform-api.company.com/provision",
"method": "POST",
"headers": {
"Authorization": "Bearer {{ .secrets.TERRAFORM_TOKEN }}",
"Content-Type": "application/json"
},
"body": {
"workspace": "{{ .entity.identifier }}-{{ .inputs.environment }}",
"variables": {
"environment": "{{ .inputs.environment }}",
"instance_type": "{{ .inputs.instance_type }}",
"region": "{{ .inputs.region }}",
"auto_scaling": "{{ .inputs.auto_scaling }}",
"service_name": "{{ .entity.identifier }}"
}
}
}
}
Cartes de pointage et normes
Définition du tableau de bord
{
"identifier": "production_readiness",
"title": "Production Readiness",
"description": "Measures how ready a service is for production deployment",
"filter": {
"combinator": "and",
"rules": [
{
"property": "$blueprint",
"operator": "=",
"value": "service"
},
{
"property": "lifecycle",
"operator": "in",
"value": ["Production", "Staging"]
}
]
},
"rules": [
{
"identifier": "has_readme",
"title": "Has README",
"description": "Service repository contains a README file",
"level": "Bronze",
"query": {
"combinator": "and",
"rules": [
{
"property": "has_readme",
"operator": "=",
"value": true
}
]
}
},
{
"identifier": "has_tests",
"title": "Has Tests",
"description": "Service has automated tests with >80% coverage",
"level": "Silver",
"query": {
"combinator": "and",
"rules": [
{
"property": "test_coverage",
"operator": ">=",
"value": 80
}
]
}
},
{
"identifier": "has_monitoring",
"title": "Has Monitoring",
"description": "Service has monitoring and alerting configured",
"level": "Gold",
"query": {
"combinator": "and",
"rules": [
{
"property": "has_monitoring",
"operator": "=",
"value": true
},
{
"property": "has_alerts",
"operator": "=",
"value": true
}
]
}
}
]
}
Portails de qualité
{
"identifier": "security_compliance",
"title": "Security Compliance",
"description": "Ensures services meet security standards",
"filter": {
"combinator": "and",
"rules": [
{
"property": "$blueprint",
"operator": "=",
"value": "service"
}
]
},
"rules": [
{
"identifier": "vulnerability_scan",
"title": "No Critical Vulnerabilities",
"description": "Service has no critical security vulnerabilities",
"level": "Bronze",
"query": {
"combinator": "and",
"rules": [
{
"property": "critical_vulnerabilities",
"operator": "=",
"value": 0
}
]
}
},
{
"identifier": "secrets_management",
"title": "Proper Secrets Management",
"description": "Service uses proper secrets management",
"level": "Silver",
"query": {
"combinator": "and",
"rules": [
{
"property": "uses_secrets_manager",
"operator": "=",
"value": true
},
{
"property": "hardcoded_secrets",
"operator": "=",
"value": 0
}
]
}
},
{
"identifier": "security_review",
"title": "Security Review Completed",
"description": "Service has completed security review",
"level": "Gold",
"query": {
"combinator": "and",
"rules": [
{
"property": "security_review_status",
"operator": "=",
"value": "approved"
}
]
}
}
]
}
Tableaux de bord et visualisation
Tableau de bord personnalisé
{
"identifier": "engineering_overview",
"title": "Engineering Overview",
"description": "High-level view of engineering metrics",
"widgets": [
{
"id": "services_by_team",
"title": "Services by Team",
"type": "pie-chart",
"dataset": {
"combinator": "and",
"rules": [
{
"property": "$blueprint",
"operator": "=",
"value": "service"
}
]
},
"property": "team"
},
{
"id": "deployment_frequency",
"title": "Deployment Frequency",
"type": "line-chart",
"dataset": {
"combinator": "and",
"rules": [
{
"property": "$blueprint",
"operator": "=",
"value": "deployment"
}
]
},
"property": "$createdAt",
"timeframe": "last30days"
},
{
"id": "production_readiness",
"title": "Production Readiness Score",
"type": "number",
"dataset": {
"combinator": "and",
"rules": [
{
"property": "$blueprint",
"operator": "=",
"value": "service"
},
{
"property": "lifecycle",
"operator": "=",
"value": "Production"
}
]
},
"calculation": "average",
"property": "$scorecard.production_readiness.level"
}
]
}
Tableau de bord de l'équipe
{
"identifier": "team_dashboard",
"title": "Team Dashboard",
"description": "Team-specific metrics and services",
"filters": [
{
"property": "team",
"operator": "=",
"value": "{{ user.team }}"
}
],
"widgets": [
{
"id": "my_services",
"title": "My Services",
"type": "table",
"dataset": {
"combinator": "and",
"rules": [
{
"property": "$blueprint",
"operator": "=",
"value": "service"
},
{
"property": "team",
"operator": "=",
"value": "{{ user.team }}"
}
]
},
"columns": ["title", "lifecycle", "health_status", "last_deployment"]
},
{
"id": "incident_count",
"title": "Open Incidents",
"type": "number",
"dataset": {
"combinator": "and",
"rules": [
{
"property": "$blueprint",
"operator": "=",
"value": "incident"
},
{
"property": "status",
"operator": "=",
"value": "open"
},
{
"property": "assigned_team",
"operator": "=",
"value": "{{ user.team }}"
}
]
}
}
]
}
Caractéristiques avancées
Propriétés personnalisées avec calculs
{
"identifier": "service",
"title": "Service",
"schema": {
"properties": {
"name": {
"title": "Name",
"type": "string"
},
"cpu_requests": {
"title": "CPU Requests",
"type": "number"
},
"cpu_limits": {
"title": "CPU Limits",
"type": "number"
},
"cpu_utilization": {
"title": "CPU Utilization (%)",
"type": "number",
"calculation": {
"type": "formula",
"formula": "(cpu_requests / cpu_limits) * 100"
}
},
"cost_per_month": {
"title": "Monthly Cost",
"type": "number",
"format": "currency"
},
"cost_per_request": {
"title": "Cost per Request",
"type": "number",
"calculation": {
"type": "formula",
"formula": "cost_per_month / (requests_per_month || 1)"
}
}
}
}
}
Règles d'automatisation
{
"identifier": "auto_assign_team",
"title": "Auto-assign Team Based on Repository",
"description": "Automatically assign team ownership based on repository path",
"trigger": {
"type": "entity-created",
"blueprintIdentifier": "service"
},
"conditions": [
{
"property": "repository",
"operator": "contains",
"value": "/backend/"
}
],
"actions": [
{
"type": "update-entity",
"properties": {
"team": "backend-team"
}
},
{
"type": "send-notification",
"channel": "slack",
"message": "New backend service {{ entity.title }} has been registered and assigned to backend-team"
}
]
}
Enrichissement des données
# Port data enrichment webhook
from flask import Flask, request, jsonify
import requests
import json
app = Flask(__name__)
@app.route('/enrich-service', methods=['POST'])
def enrich_service():
"""Enrich service data with external information"""
data = request.json
entity = data.get('entity', {})
# Get repository information from GitHub
repo_url = entity.get('properties', {}).get('repository')
if repo_url:
github_data = get_github_metrics(repo_url)
# Update entity with enriched data
enriched_properties = {
**entity.get('properties', {}),
'stars': github_data.get('stargazers_count', 0),
'forks': github_data.get('forks_count', 0),
'open_issues': github_data.get('open_issues_count', 0),
'last_commit': github_data.get('pushed_at'),
'primary_language': github_data.get('language')
}
# Update Port entity
update_port_entity(entity['identifier'], enriched_properties)
return jsonify({"status": "success"})
def get_github_metrics(repo_url):
"""Fetch metrics from GitHub API"""
# Extract owner/repo from URL
parts = repo_url.replace('https://github.com/', '').split('/')
owner, repo = parts[0], parts[1]
response = requests.get(
f"https://api.github.com/repos/{owner}/{repo}",
headers={"Authorization": f"token {GITHUB_TOKEN}"}
)
return response.json() if response.status_code == 200 else {}
def update_port_entity(identifier, properties):
"""Update Port entity with enriched data"""
token = get_port_access_token()
response = requests.patch(
f"{PORT_API_URL}/blueprints/service/entities/{identifier}",
headers={
"Authorization": f"Bearer {token}",
"Content-Type": "application/json"
},
json={"properties": properties}
)
return response.json()
if __name__ == '__main__':
app.run(host='0.0.0.0', port=5000)
Surveillance et observation
Intégration des contrôles de santé
import requests
import json
from datetime import datetime
def check_service_health():
"""Check health of all services and update Port"""
services = get_port_entities("service")
for service in services:
health_url = service.get('properties', {}).get('health_endpoint')
if health_url:
try:
response = requests.get(health_url, timeout=10)
health_status = "Healthy" if response.status_code == 200 else "Unhealthy"
response_time = response.elapsed.total_seconds() * 1000
# Update Port entity
update_port_entity(service['identifier'], {
'health_status': health_status,
'response_time_ms': response_time,
'last_health_check': datetime.utcnow().isoformat()
})
except requests.RequestException:
update_port_entity(service['identifier'], {
'health_status': 'Unreachable',
'last_health_check': datetime.utcnow().isoformat()
})
def get_port_entities(blueprint):
"""Fetch entities from Port"""
token = get_port_access_token()
response = requests.get(
f"{PORT_API_URL}/blueprints/{blueprint}/entities",
headers={"Authorization": f"Bearer {token}"}
)
return response.json().get('entities', [])
# Run health checks every 5 minutes
if __name__ == '__main__':
import schedule
import time
schedule.every(5).minutes.do(check_service_health)
while True:
schedule.run_pending()
time.sleep(1)
Collecte de données
import requests
import json
from prometheus_client.parser import text_string_to_metric_families
def collect_prometheus_metrics():
"""Collect metrics from Prometheus and update Port"""
services = get_port_entities("service")
for service in services:
service_name = service['identifier']
# Query Prometheus for service metrics
metrics = {
'cpu_usage': query_prometheus(f'avg(cpu_usage{{service="{service_name}"}})'),
'memory_usage': query_prometheus(f'avg(memory_usage{{service="{service_name}"}})'),
'request_rate': query_prometheus(f'rate(http_requests_total{{service="{service_name}"}}[5m])'),
'error_rate': query_prometheus(f'rate(http_requests_total{{service="{service_name}",status=~"5.."}[5m])'),
'p95_latency': query_prometheus(f'histogram_quantile(0.95, http_request_duration_seconds{{service="{service_name}"}})'),
}
# Update Port entity with metrics
update_port_entity(service['identifier'], {
'cpu_usage_percent': metrics['cpu_usage'],
'memory_usage_percent': metrics['memory_usage'],
'requests_per_second': metrics['request_rate'],
'error_rate_percent': metrics['error_rate'] * 100,
'p95_latency_ms': metrics['p95_latency'] * 1000,
'metrics_last_updated': datetime.utcnow().isoformat()
})
def query_prometheus(query):
"""Query Prometheus for metrics"""
response = requests.get(
f"{PROMETHEUS_URL}/api/v1/query",
params={'query': query}
)
data = response.json()
if data['status'] == 'success' and data['data']['result']:
return float(data['data']['result'][0]['value'][1])
return 0
Sécurité et conformité
RBAC Configuration
{
"roles": [
{
"identifier": "developer",
"title": "Developer",
"description": "Standard developer access",
"permissions": [
{
"action": "read",
"resource": "entity",
"condition": {
"property": "team",
"operator": "=",
"value": "{{ user.team }}"
}
},
{
"action": "execute",
"resource": "action",
"condition": {
"property": "identifier",
"operator": "in",
"value": ["deploy_service", "restart_service"]
}
}
]
},
{
"identifier": "team_lead",
"title": "Team Lead",
"description": "Team lead with additional permissions",
"permissions": [
{
"action": "*",
"resource": "entity",
"condition": {
"property": "team",
"operator": "=",
"value": "{{ user.team }}"
}
},
{
"action": "execute",
"resource": "action",
"condition": {
"property": "approval_required",
"operator": "=",
"value": false
}
}
]
},
{
"identifier": "platform_admin",
"title": "Platform Admin",
"description": "Full platform access",
"permissions": [
{
"action": "*",
"resource": "*"
}
]
}
]
}
Comptabilisation des audits
import json
from datetime import datetime
import logging
# Configure audit logger
audit_logger = logging.getLogger('port_audit')
audit_handler = logging.FileHandler('port_audit.log')
audit_formatter = logging.Formatter('%(asctime)s - %(message)s')
audit_handler.setFormatter(audit_formatter)
audit_logger.addHandler(audit_handler)
audit_logger.setLevel(logging.INFO)
def log_audit_event(event_type, user, entity, action, details=None):
"""Log audit events for compliance"""
audit_event = {
'timestamp': datetime.utcnow().isoformat(),
'event_type': event_type,
'user': {
'id': user.get('id'),
'email': user.get('email'),
'team': user.get('team')
},
'entity': {
'identifier': entity.get('identifier'),
'blueprint': entity.get('blueprint'),
'title': entity.get('title')
},
'action': action,
'details': details or {},
'ip_address': get_client_ip(),
'user_agent': get_user_agent()
}
audit_logger.info(json.dumps(audit_event))
# Example usage in webhook handler
@app.route('/port-action', methods=['POST'])
def handle_port_action():
data = request.json
# Log the action execution
log_audit_event(
event_type='action_executed',
user=data.get('trigger', {}).get('by', {}),
entity=data.get('entity', {}),
action=data.get('action', {}).get('identifier'),
details={
'inputs': data.get('payload', {}).get('inputs', {}),
'run_id': data.get('run', {}).get('id')
}
)
# Process the action
result = process_action(data)
# Log the result
log_audit_event(
event_type='action_completed',
user=data.get('trigger', {}).get('by', {}),
entity=data.get('entity', {}),
action=data.get('action', {}).get('identifier'),
details={
'status': result.get('status'),
'duration': result.get('duration'),
'output': result.get('output')
}
)
return jsonify(result)
Meilleures pratiques
Conception du modèle de données
# Best practices for blueprint design:
# 1. Start with core entities (services, teams, environments)
# 2. Use consistent naming conventions
# 3. Define clear relationships between entities
# 4. Include metadata for governance (owner, lifecycle, tier)
# 5. Plan for scalability and evolution
# 6. Use enums for standardized values
# 7. Include validation rules
# 8. Design for automation and self-service
Stratégie d'intégration
# Integration best practices:
# 1. Start with read-only integrations
# 2. Implement gradual data ingestion
# 3. Use webhooks for real-time updates
# 4. Implement proper error handling and retries
# 5. Monitor integration health
# 6. Use batch processing for large datasets
# 7. Implement data validation and cleansing
# 8. Plan for data migration and evolution
Conception de l'autoservice
# Self-service action design:
# 1. Design for common use cases first
# 2. Provide clear input validation
# 3. Include helpful descriptions and examples
# 4. Implement proper approval workflows
# 5. Provide feedback and status updates
# 6. Include rollback capabilities
# 7. Monitor action usage and success rates
# 8. Iterate based on user feedback
Gouvernance et respect
# Governance best practices:
# 1. Implement proper RBAC from the start
# 2. Enable comprehensive audit logging
# 3. Define clear ownership models
# 4. Implement quality gates and scorecards
# 5. Regular compliance reviews
# 6. Automate policy enforcement
# 7. Provide training and documentation
# 8. Monitor and measure adoption
Dépannage
Questions communes
# API authentication issues
# 1. Verify client ID and secret
# 2. Check token expiration
# 3. Validate API permissions
# 4. Review rate limiting
# Data ingestion problems
# 1. Check webhook endpoints
# 2. Validate JSON schema
# 3. Review entity relationships
# 4. Check for duplicate identifiers
# Performance issues
# 1. Optimize API queries
# 2. Implement proper caching
# 3. Use batch operations
# 4. Monitor rate limits
Outils de débogage
# Port API debugging utility
import requests
import json
def debug_port_api(endpoint, method='GET', data=None):
"""Debug Port API calls with detailed logging"""
token = get_port_access_token()
headers = {
'Authorization': f'Bearer {token}',
'Content-Type': 'application/json'
}
print(f"Making {method} request to: {PORT_API_URL}{endpoint}")
print(f"Headers: {json.dumps(headers, indent=2)}")
if data:
print(f"Request body: {json.dumps(data, indent=2)}")
response = requests.request(
method=method,
url=f"{PORT_API_URL}{endpoint}",
headers=headers,
json=data
)
print(f"Response status: {response.status_code}")
print(f"Response headers: {dict(response.headers)}")
print(f"Response body: {json.dumps(response.json(), indent=2)}")
return response
# Example usage
debug_port_api('/blueprints/service/entities')
Ressources
Documentation
- [Documentation de port] (LINK_9)
- [Référence API] (LINK_9)
- [Guides d'intégration] (LINK_9)
Communauté
- Communauté portuaire
- [Communauté Slack] (LINK_9)
- [Exemples de GitHub] (LINK_9)
Formation
- [Académie des ports] (LINK_9)
- [Série Webinaire] (LINK_9)
- [Guide des meilleures pratiques] (LINK_9)