README
ΒΆ
π Pre-Release Notice
osmanageis currently in alpha/pre-release stage and is being actively developed for production use at Intevation GmbH. While the tool is functional, it is not yet ready for general community adoption:
- APIs and command interfaces may change
- Some features are still being finalized
- Documentation is work-in-progress
- Production hardening is ongoing
We plan to release a stable, community-ready version in the future. For now, use at your own risk or for experimentation only. Contributions and feedback are welcome!
osmanage
A command-line interface for managing OpenSlides instances. This tool provides direct access to OpenSlides backend actions, datastore queries, database migrations, and deployment setup.
Table of Contents
Overview
osmanage is a comprehensive management utility for OpenSlides 4.x instances. It combines deployment automation, database operations, and administrative tasks into a single tool.
Key Features:
- Deployment Setup: Generate Docker Compose and Kubernetes configurations
- Secrets Management: Automatic generation of secure passwords and certificates
- Datastore Queries: Direct PostgreSQL access with advanced filtering
- Database Migrations: Manage OpenSlides schema migrations with progress tracking
- User Management: Create users and manage passwords
- Backend Actions: Execute arbitrary OpenSlides actions
Installation
Binary Release
Download the latest binary from the releases page:
# Linux AMD64
curl -L https://github.com/OpenSlides/openslides-cli/releases/latest/download/osmanage -o osmanage
chmod +x osmanage
sudo mv osmanage /usr/local/bin/
From Source
Requirements:
- Go 1.23 or later
git clone https://github.com/OpenSlides/openslides-cli.git
cd openslides-cli
CGO_ENABLED=0 go build -a -ldflags="-s -w" ./cmd/osmanage
Quick Start
Standard Setup (Auto-Initialize)
If your config has OPENSLIDES_BACKEND_CREATE_INITIAL_DATA: 1 set (default):
# 1. Generate deployment configuration
osmanage setup ./openslides-deployment \
--config config.yml \
--template templates/docker-compose.yml
# 2. Start services
cd openslides-deployment
docker compose up -d
# 3. Wait for services to be ready (~30 seconds)
docker compose logs -f backendManage
# 4. Access OpenSlides at http://localhost:8000
# Login as 'superadmin' with password from:
cat secrets/superadmin
# 5. Stop services when done
docker compose down
# Optional: Remove volumes (complete cleanup)
docker compose down -v
Commands
setup
Creates deployment configuration files, secrets, and SSL certificates.
Usage:
osmanage setup <directory> [flags]
Flags:
-t, --template <path>: Custom template file or directory-c, --config <files>: YAML config file(s) (can be used multiple times)-f, --force: Overwrite existing files
Generated Files:
docker-compose.ymlor Kubernetes manifestssecrets/directory with:auth_token_keyauth_cookie_keyinternal_auth_passwordpostgres_passwordsuperadmincert_crtandcert_key(if HTTPS enabled)
Example:
osmanage setup ./deployment \
--config config.yml \
--template templates/docker-compose.yml
action
Execute arbitrary OpenSlides backend actions.
Usage:
osmanage action <action-name> [payload] [flags]
Flags:
-a, --address: Backend service address (default:localhost:9002)--password-file: Authorization password file (default:secrets/internal_auth_password)-f, --file: JSON payload file or-for stdin
Examples:
# Inline JSON
osmanage action meeting.create '[{"name": "Annual Meeting", "committee_id": 1, "language": "de", "admin_ids": [1]}]'
# From file
osmanage action meeting.create --file meeting.json
# From stdin
echo '[{"name": "Test Meeting", "committee_id": 1, "language": "de", "admin_ids": [1]}]' | osmanage action meeting.create --file -
create-user
Create a new OpenSlides user.
Usage:
osmanage create-user [user-data] [flags]
Flags:
-a, --address: Backend service address (default:localhost:9002)--password-file: Authorization password file (default:secrets/internal_auth_password)-f, --file: JSON user data file or-for stdin
Required Fields:
username: User login namedefault_password: Initial password
Example:
# From file
osmanage create-user --file user.json
# Inline
osmanage create-user '{"username": "admin", "default_password": "secret123", "first_name": "Admin", "last_name": "User"}'
user.json:
{
"username": "mmax",
"default_password": "changemepwd",
"first_name": "Max",
"last_name": "Mustermann",
"email": "[email protected]",
"is_active": true
}
get
Query the OpenSlides datastore with advanced filtering.
Usage:
osmanage get <collection> [flags]
Supported Collections:
usermeetingorganization
Flags:
--postgres-host: PostgreSQL host (default:localhost)--postgres-port: PostgreSQL port (default:5432)--postgres-user: PostgreSQL user (default:instance_user)--postgres-database: PostgreSQL database (default:instance_db)--postgres-password-file: Password file (default:/secrets/postgres-password)--fields: Comma-separated field list--filter: Simple key=value filters (multiple allowed, AND'ed together)--filter-raw: Complex JSON filter with operators--exists: Return boolean (requires filter)
Supported Operators (in --filter-raw):
=: Equal!=: Not equal>: Greater than<: Less than>=: Greater than or equal<=: Less than or equal~=: Regex match
Examples:
Simple queries:
# Get all users with specific fields
osmanage get user --fields first_name,last_name,email
# Filter by equality
osmanage get user --filter is_active=true --filter username=admin
# Check existence
osmanage get meeting --filter id=1 --exists
Complex filters:
# Numeric comparison
osmanage get user --filter-raw '{"field":"id","operator":">","value":10}'
# Regex matching
osmanage get user --filter-raw '{"field":"username","operator":"~=","value":"^admin"}'
# AND filter
osmanage get user --filter-raw '{
"and_filter": [
{"field": "is_active", "operator": "=", "value": true},
{"field": "first_name", "operator": "~=", "value": "^M"}
]
}'
# OR filter
osmanage get meeting --filter-raw '{
"or_filter": [
{"field": "name", "operator": "~=", "value": "Annual"},
{"field": "name", "operator": "~=", "value": "Board"}
]
}'
# NOT filter
osmanage get user --filter-raw '{
"not_filter": {
"field": "is_active",
"operator": "=",
"value": false
}
}'
# Nested filters
osmanage get user --filter-raw '{
"and_filter": [
{"field": "is_active", "operator": "=", "value": true},
{
"or_filter": [
{"field": "username", "operator": "~=", "value": "^admin"},
{"field": "username", "operator": "~=", "value": "^super"}
]
}
]
}'
Output Format:
{
"1": {
"id": 1,
"username": "admin",
"first_name": "Admin",
"last_name": "User",
"is_active": true
},
"2": {
"id": 2,
"username": "mmax",
"first_name": "Max",
"last_name": "Mustermann",
"is_active": true
}
}
initial-data
Initialize a new OpenSlides datastore.
Usage:
osmanage initial-data [flags]
Flags:
-a, --address: Backend service address (default:localhost:9002)--password-file: Authorization password file (default:secrets/internal_auth_password)--superadmin-password-file: Superadmin password file (default:secrets/superadmin)-f, --file: JSON initial data file or-for stdin
Behavior:
- Sets up organization and default data
- Sets superadmin (user ID 1) password
- Returns error if datastore is not empty (exit code 2)
Example:
# With default data
osmanage initial-data \
--address localhost:9002 \
--password-file secrets/internal_auth_password \
--superadmin-password-file secrets/superadmin
# With custom initial data
osmanage initial-data \
--address localhost:9002 \
--password-file secrets/internal_auth_password \
--superadmin-password-file secrets/superadmin \
--file initial-data.json
migrations
Manage OpenSlides database migrations.
Subcommands:
migrate: Prepare migrations (dry-run)finalize: Prepare and apply migrationsreset: Reset unapplied migrationsclear-collectionfield-tables: Clear auxiliary tables (offline only)stats: Show migration statisticsprogress: Query progress of running migration
Common Flags:
-a, --address: Backend service address (default:localhost:9002)--password-file: Authorization password file (default:secrets/internal_auth_password)--interval: Progress polling interval (default:1s, use0to disable)
Features:
- Automatic retry with exponential backoff
- Real-time progress tracking
- Context-aware timeouts
- Network error handling
Examples:
# Prepare migrations (dry-run)
osmanage migrations migrate --address localhost:9002
# Apply migrations with progress
osmanage migrations finalize \
--address localhost:9002 \
--password-file secrets/internal_auth_password
# Apply migrations without progress output
osmanage migrations finalize \
--address localhost:9002 \
--interval 0
# Check migration status
osmanage migrations stats --address localhost:9002
# Monitor running migration
osmanage migrations progress --address localhost:9002
# Reset migrations
osmanage migrations reset --address localhost:9002
Migration Stats Output:
current_migration_index: 15
target_migration_index: 20
positions: 1500
events: 5000
partially_migrated_positions: 500
fully_migrated_positions: 1000
status: migration_running
set
Update OpenSlides objects using backend actions.
Usage:
osmanage set <action> [payload] [flags]
Supported Actions:
agenda_itemcommitteegroupmeetingmotionorganizationorganization_tagprojectorthemetopicuser
Flags:
-a, --address: Backend service address (default:localhost:9002)--password-file: Authorization password file (default:secrets/internal_auth_password)-f, --file: JSON payload file or-for stdin
Examples:
# Update user
osmanage set user '[{"id": 5, "first_name": "Jane", "last_name": "Smith"}]'
# Update meeting from file
osmanage set meeting --file meeting-update.json
# Update organization
osmanage set organization '[{"id": 1, "name": "Updated Organization Name"}]'
set-password
Change a user's password.
Usage:
osmanage set-password [flags]
Flags:
-a, --address: Backend service address (default:localhost:9002)--password-file: Authorization password file (default:secrets/internal_auth_password)-u, --user_id: User ID (required)-p, --password: New password (required)
Example:
osmanage set-password \
--address localhost:9002 \
--user_id 5 \
--password "newSecurePassword123"
Configuration
Logging Levels
Set via the --log-level flag (applies to all commands):
osmanage --log-level debug get user
Available levels:
debug: Detailed diagnostic informationinfo: General informational messages (default)warn: Warning messageserror: Error messages only
Example output:
[INFO] === GET COLLECTION ===
[DEBUG] Collection: user
[DEBUG] Found 150 total users
[DEBUG] Fields to fetch: [id first_name last_name email is_active]
[INFO] Query completed successfully
Examples
Complete Setup Workflow
# 1. Generate deployment configuration
osmanage setup ./openslides-deployment \
--config config.yml \
--template templates/docker-compose.yml
# 2. Start services (Docker Compose example)
cd openslides-deployment
docker-compose up -d
# 3. Access OpenSlides
# Visit http://localhost:8000
# Login as 'superadmin' with password from:
cat secrets/superadmin
Backup User Data
# Export all users to JSON
osmanage get user > backup-users-$(date +%Y%m%d).json
# Export specific fields only
osmanage get user \
--fields username,first_name,last_name,email \
> backup-users-minimal.json
Query Active Meetings
# Get all active meetings with details
osmanage get meeting \
--filter is_active_in_organization_id=1 \
--fields name,start_time,end_time,location
# Count active meetings
osmanage get meeting \
--filter is_active_in_organization_id=1 \
| jq 'length'
# See if an active meeting exists by id
osmanage get meeting \
--filter-raw '{"and_filter": [{"field": "id", "operator": "=", "value": 1}, {"field": "is_active_in_organization_id", "operator": "=", "value": 1}]}'
--exists
# easier (id=5)
osmanage get meeting --filter is_active_in_organization=1 --fields name | jq '. "5"'
Development
Project Structure
openslides-cli/
βββ cmd/
β βββ osmanage/ # Main entry point
β βββ main.go
βββ internal/
β βββ actions/ # Action commands
β β βββ action/
β β β βββ action.go
β β βββ createuser/
β β β βββ createuser.go
β β βββ get/
β β β βββ get.go
β β β βββ get_test.go
β β βββ initialdata/
β β β βββ initialdata.go
β β βββ set/
β β β βββ set.go
β β βββ setpassword/
β β βββ setpassword.go
β βββ client/ # HTTP client
β β βββ client.go
β β βββ client_test.go
β βββ logger/ # Logging
β β βββ logger.go
β β βββ logger_test.go
β βββ migrations/ # Migration commands
β β βββ migrations.go
β β βββ migrations_test.go
β βββ templating/ # Setup & templating
β β βββ config/
β β βββ setup/
β βββ utils/ # Utilities
β βββ utils.go
β βββ utils_test.go
βββ go.mod
βββ go.sum
βββ README.md
βββ LICENSE
Running Tests
# Run all tests
go test ./...
# Run tests with coverage
go test -cover ./...
Building
# Build for testing (bigger binary, debuggable)
go build -o osmanage ./cmd/osmanage
# Build for prod (smaller binary, no C code, no debug)
CGO_ENABLED=0 go build -a -ldflags="-s -w" -o osmanage ./cmd/osmanage
Contributing
- Fork the repository
- Create a feature branch (
git checkout -b feature/amazing-feature) - Write tests for your changes
- Ensure all tests pass (
go test ./...) - Commit your changes (
git commit -m 'Add amazing feature') - Push to the branch (
git push origin feature/amazing-feature) - Open a Pull Request
Code Style:
- Follow standard Go conventions
- Run
go fmtbefore committing - Add tests for new functionality
- Update documentation as needed
Credits
This tool represents a significant refactor and expansion of the original openslides-manage-service created by Norman JΓ€ckel.
Major Changes from Original:
- Migration from
datastorereadertoopenslides-go/datastore/dsfetch - Removed gRPC
- Filtering in-memory (until better solution is found -> TODO)
- retry mechanism for migrations
- Comprehensive test coverage
- Improved deployment configuration system
- Simplified the templating
Refactored/Developed by: Alexej Antoni @ Intevation GmbH
Original work by: Norman JΓ€ckel
License
This project is licensed under the MIT License - see the LICENSE file for details.
Support
- Issues: GitHub Issues
- Discussions: GitHub Discussions