Setting the file. One moment.
Subchapter 22.1
references/admin-tooling.mdMarkdown14 KBView on GitHub
Build CLI tools and admin utilities for project management at scale.
Build a comprehensive CLI tool:
# cli/ldprojects.py
import click
import json
from tabulate import tabulate
from launchdarkly.projects import ProjectManager
pm = ProjectManager()
@click.group()
@click.option('--api-token', envvar='LAUNCHDARKLY_API_TOKEN', help='LaunchDarkly API token')
@click.pass_context
def cli(ctx, api_token):
"""LaunchDarkly project management CLI."""
Install dependencies:
pip install click tabulateUsage:
# Create project
python cli/ldprojects.py create "My Agent" my-ai -t ai-configs -t production
# List projects
python cli/ldprojects.py list
python cli/ldprojects.py list --format json
python cli/ldprojects.py list --filter-tag ai-configs
# Get SDK key
python cli/ldprojects.py get-key my-ai
python cli/ldprojects.py get-key my-ai --env test --show-key
# Clone project
python cli/ldprojects.py clone template-ai new-ai "New Agent Project"
# Export keys
python cli/ldprojects.py export-keys my-ai -o keys.json
# Bulk create
python cli/ldprojects.py bulk-create projects.csv --execute
# Audit
python cli/ldprojects.py auditBuild a simple web dashboard:
# admin/app.py
from flask import Flask, render_template, request, redirect, jsonify
from launchdarkly.projects import ProjectManager
app = Flask(__name__)
pm = ProjectManager()
@app.route('/')
def index():
projects = pm.list_projects()
return render_template('index.html', projects=projects)
@app.route('/projects', methods=['POST'])
def create_project():
data = request.json
project = pm.create_project(
name=data['name'],
key=data['key'],
tags=data.get('tags', [])
)
return jsonify(project)
@app.route('/projects/<key>')
def project_detail(key):
project = pm.get_project(key)
return render_template('project.html', project=project)
@app.route('/projects/<key>/keys/<env>')
def get_sdk_key(key, env):
sdk_key = pm.get_sdk_key(key, env)
return jsonify({'sdkKey': sdk_key})
if __name__ == '__main__':
app.run(debug=True, port=5000)templates/index.html:
<!DOCTYPE html>
<html>
<head>
<title>LaunchDarkly Projects Admin</title>
<style>
body { font-family: Arial, sans-serif; margin: 40px; }
.project { border: 1px solid #ddd; padding: 15px; margin: 10px 0; }
.tags { color: #666; font-size: 0.9em; }
</style>
</head>
<body>
<h1>LaunchDarkly Projects</h1>
<h2>Create New Project</h2>
<form id="createForm">
<input type="text" name="name" placeholder="Project Name" required>
<input type="text" name="key" placeholder="project-key" required>
<input type="text" name="tags" placeholder="tag1,tag2">
<button type="submit">Create</button>
</form>
<h2>Existing Projects</h2>
{% for project in projects %}
<div class="project">
<h3><a href="/projects/{{ project.key }}">{{ project.name }}</a></h3>
<p><strong>Key:</strong> {{ project.key }}</p>
<p class="tags"><strong>Tags:</strong> {{ project.tags|join(', ') }}</p>
</div>
{% endfor %}
<script>
document.getElementById('createForm').onsubmit = async (e) => {
e.preventDefault();
const formData = new FormData(e.target);
const data = {
name: formData.get('name'),
key: formData.get('key'),
tags: formData.get('tags').split(',').filter(t => t.trim())
};
const resp = await fetch('/projects', {
method: 'POST',
headers: {'Content-Type': 'application/json'},
body: JSON.stringify(data)
});
if (resp.ok) {
location.reload();
} else {
alert('Failed to create project');
}
};
</script>
</body>
</html>Run the dashboard:
pip install flask
python admin/app.py
# Visit http://localhost:5000Monitor project creation and usage:
# monitoring/project_monitor.py
import time
from datetime import datetime
from launchdarkly.projects import ProjectManager
class ProjectMonitor:
"""Monitor LaunchDarkly projects for changes."""
def __init__(self):
self.pm = ProjectManager()
self.known_projects = set()
def check_for_new_projects(self):
"""Check for newly created projects."""
projects = self.pm.list_projects()
current_keys = {p['key'] for p in projects}
new_projects = current_keys - self.known_projects
if new_projects:
self.on_new_projects(new_projects, projects)
self.known_projects = current_keys
def on_new_projects(self, new_keys, all_projects):
"""Handle new projects."""
for key in new_keys:
project = next(p for p in all_projects if p['key'] == key)
print(f"[{datetime.now()}] New project detected: {project['name']} ({key})")
# Send alert, log to DB, etc.
def run(self, interval=60):
"""Run monitor continuously."""
print(f"Starting project monitor (interval: {interval}s)")
while True:
try:
self.check_for_new_projects()
except Exception as e:
print(f"Error: {e}")
time.sleep(interval)
if __name__ == '__main__':
monitor = ProjectMonitor()
monitor.run()Backup project configurations:
# backup/project_backup.py
import json
from datetime import datetime
from launchdarkly.projects import ProjectManager
def backup_all_projects(output_file=None):
"""Backup all projects to JSON file."""
pm = ProjectManager()
projects = pm.list_projects()
if not output_file:
timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
output_file = f"projects_backup_{timestamp}.json"
with open(output_file, 'w') as f:
json.dump(projects, f, indent=2)
print(f"✓ Backed up {len(projects)} projects to {output_file}")
return output_file
def restore_projects(backup_file):
"""Restore projects from backup (creates if missing)."""
pm = ProjectManager()
with open(backup_file, 'r') as f:
projects = json.load(f)
for project in projects:
try:
pm.create_project(
name=project['name'],
key=project['key'],
tags=project.get('tags', [])
)
print(f"✓ Restored: {project['key']}")
except Exception as e:
print(f"✗ Failed to restore {project['key']}: {e}")
# Usage
backup_all_projects()
# restore_projects('projects_backup_20260205_120000.json')Export projects to Terraform format:
# terraform/export_terraform.py
def export_to_terraform(project_keys=None):
"""Export projects as Terraform configuration."""
pm = ProjectManager()
projects = pm.list_projects()
if project_keys:
projects = [p for p in projects if p['key'] in project_keys]
tf_config = []
for project in projects:
resource_name = project['key'].replace('-', '_')
tags = ', '.join(f'"{tag}"' for tag in project.get('tags', []))
tf_config.append(f'''
resource "launchdarkly_project" "{resource_name}" {{
key = "{project['key']}"
name = "{project['name']}"
tags = [{tags}]
}}
''')
output = '\n'.join(tf_config)
with open('projects.tf', 'w') as f:
f.write(output)
print(f"✓ Exported {len(projects)} projects to projects.tf")
# Usage
export_to_terraform()Send notifications to Slack:
# integrations/slack_notifier.py
import requests
def notify_slack(webhook_url, message):
"""Send notification to Slack."""
requests.post(webhook_url, json={'text': message})
def notify_project_created(project, webhook_url):
"""Notify Slack when project is created."""
message = f"🎉 New LaunchDarkly project created: *{project['name']}* (`{project['key']}`)"
notify_slack(webhook_url, message)
# Usage in CLI
@cli.command()
@click.argument('name')
@click.argument('key')
@click.option('--slack-webhook', envvar='SLACK_WEBHOOK_URL')
@click.pass_obj
def create_with_notification(pm, name, key, slack_webhook):
"""Create project and notify Slack."""
project = pm.create_project(name, key, [])
click.echo(f"✓ Created: {project['name']}")
if slack_webhook:
notify_project_created(project, slack_webhook)
click.echo("✓ Notified Slack")