Skip to content

Commit a975080

Browse files
committed
dockerized and bug fixes
1 parent 247fa94 commit a975080

17 files changed

+697
-172
lines changed

DOCKER.md

Lines changed: 106 additions & 88 deletions
Original file line numberDiff line numberDiff line change
@@ -32,19 +32,57 @@ The following environment variables can be configured in `docker-compose.yml`:
3232

3333
- `PYTHONPATH`: Set to `/app` (default)
3434
- `LOG_LEVEL`: Set to `info` (default)
35+
- `DATABASE_URL`: Set to `sqlite:////app/db/scim.db` (default)
3536

3637
### Volumes
3738

38-
The following directories are mounted for persistence:
39+
The following volumes are configured for persistence:
3940

40-
- `./scim.db``/app/scim.db` (main database)
41-
- `./logs``/app/logs` (application logs)
42-
- `./test_scim.db``/app/test_scim.db` (test database)
41+
- `scim_database``/app/db` (main database - Docker volume)
42+
- `./logs``/app/logs` (application logs - bind mount)
43+
44+
**Database Volume**: The `scim_database` volume is a Docker-managed volume that persists across container restarts and reboots. This ensures your SCIM server data is preserved even when containers are recreated.
4345

4446
### Ports
4547

4648
- `7001` - Main SCIM server port
4749

50+
## Database Persistence
51+
52+
### Docker Volume Benefits
53+
54+
- **Persistent Storage**: Database survives container restarts and reboots
55+
- **Isolated Storage**: Database is managed by Docker and isolated from host filesystem
56+
- **Easy Backup**: Volume can be easily backed up using Docker commands
57+
- **Performance**: Better I/O performance compared to bind mounts
58+
59+
### Managing the Database Volume
60+
61+
**List volumes:**
62+
```bash
63+
docker volume ls
64+
```
65+
66+
**Inspect volume details:**
67+
```bash
68+
docker volume inspect scim_database
69+
```
70+
71+
**Backup the database:**
72+
```bash
73+
docker run --rm -v scim_database:/data -v $(pwd):/backup alpine tar czf /backup/scim_database_backup.tar.gz -C /data .
74+
```
75+
76+
**Restore the database:**
77+
```bash
78+
docker run --rm -v scim_database:/data -v $(pwd):/backup alpine tar xzf /backup/scim_database_backup.tar.gz -C /data
79+
```
80+
81+
**Remove the volume (WARNING: This will delete all data):**
82+
```bash
83+
docker volume rm scim_database
84+
```
85+
4886
## Health Checks
4987

5088
The container includes robust health checks that verify the application is running properly:
@@ -91,123 +129,103 @@ docker build -t scim-server .
91129
### Running the Container
92130

93131
```bash
94-
docker run -p 7001:7001 -v $(pwd)/scim.db:/app/scim.db -v $(pwd)/logs:/app/logs scim-server
132+
docker run -p 7001:7001 -v scim_database:/app/db -v $(pwd)/logs:/app/logs scim-server
95133
```
96134

97135
### Viewing Logs
98136

99137
```bash
100138
# Docker Compose logs
101-
docker-compose logs -f
139+
docker-compose logs -f scim-server
102140

103141
# Direct container logs
104-
docker logs scim-server
142+
docker logs -f scim-server
105143
```
106144

107-
### Checking Health Status
145+
### Database Initialization
108146

109-
```bash
110-
# Check container health status
111-
docker ps
147+
The container automatically initializes the database on first startup. The startup script (`start.sh`) checks if the database file exists and initializes it if needed.
112148

113-
# Check health check logs
114-
docker inspect scim-server | grep -A 10 "Health"
149+
**Manual database initialization:**
150+
```bash
151+
docker exec scim-server python scripts/init_db.py
115152
```
116153

117-
## API Endpoints
118-
119-
Once running, the SCIM server will be available at:
120-
121-
- Health Check: `http://localhost:7001/healthz`
122-
- Detailed Health: `http://localhost:7001/health`
123-
- SCIM Endpoints: `http://localhost:7001/scim-identifier/{server_id}/scim/v2/`
124-
125-
## Troubleshooting
126-
127-
### Container Won't Start
154+
### CLI Access
128155

129-
1. Check if port 7001 is already in use:
130-
```bash
131-
lsof -i :7001
132-
```
156+
Access the SCIM CLI from within the container:
133157

134-
2. Check container logs:
135-
```bash
136-
docker-compose logs
137-
```
158+
```bash
159+
# List all servers
160+
docker exec scim-server python scripts/scim_cli.py list
138161

139-
3. Check health check status:
140-
```bash
141-
docker ps
142-
docker inspect scim-server
143-
```
162+
# Create a new server
163+
docker exec scim-server python scripts/scim_cli.py create --app-profile hr --defaults
144164

145-
### Health Check Failures
165+
# Create server with specific ID
166+
docker exec scim-server python scripts/scim_cli.py create --server-id your-server-id --app-profile hr --defaults
167+
```
146168

147-
If health checks are failing:
169+
## Troubleshooting
148170

149-
1. Check if the application is starting properly:
150-
```bash
151-
docker-compose logs scim-server
152-
```
171+
### Database Issues
153172

154-
2. Test the health endpoint manually:
155-
```bash
156-
curl http://localhost:7001/healthz
157-
curl http://localhost:7001/health
158-
```
173+
**Check if database exists:**
174+
```bash
175+
docker exec scim-server ls -la /app/db/
176+
```
159177

160-
3. Verify the container is running:
161-
```bash
162-
docker exec scim-server ps aux
163-
```
178+
**Check database contents:**
179+
```bash
180+
docker exec scim-server python -c "import sqlite3; conn = sqlite3.connect('/app/db/scim.db'); cursor = conn.cursor(); cursor.execute('SELECT COUNT(*) FROM users'); print('Users:', cursor.fetchone()[0]); conn.close()"
181+
```
164182

165-
### IP Restriction Issues
183+
**Reset database (WARNING: This will delete all data):**
184+
```bash
185+
docker exec scim-server python scripts/scim_cli.py reset
186+
```
166187

167-
If you're getting "Access denied from external network" errors when accessing `/health`:
188+
### Volume Issues
168189

169-
1. **From Docker container**: The `/health` endpoint is restricted to internal networks only
170-
2. **From host machine**: Use `localhost` or `127.0.0.1` to access the endpoint
171-
3. **From external networks**: Use `/healthz` instead, which is publicly accessible
172-
4. **For monitoring systems**: Configure your monitoring to use `/healthz` for external checks
190+
**Check volume status:**
191+
```bash
192+
docker volume ls | grep scim_database
193+
```
173194

174-
**Allowed networks for `/health`**:
175-
- Localhost: `127.0.0.1`, `::1`
176-
- Private networks: `10.0.0.0/8`, `172.16.0.0/12`, `192.168.0.0/16`
177-
- Docker networks: `172.16.0.0/12`, `192.168.0.0/16`
178-
- Link-local: `169.254.0.0/16`, `fe80::/10`
195+
**Inspect volume:**
196+
```bash
197+
docker volume inspect scim_database
198+
```
179199

180-
### Database Issues
200+
**Recreate volume (WARNING: This will delete all data):**
201+
```bash
202+
docker-compose down
203+
docker volume rm scim_database
204+
docker-compose up --build
205+
```
181206

182-
If you encounter database issues, you can reset the database:
207+
## Production Considerations
183208

184-
1. Stop the container:
185-
```bash
186-
docker-compose down
187-
```
209+
### Security
188210

189-
2. Remove the database file:
190-
```bash
191-
rm scim.db
192-
```
211+
- The container runs as root for simplicity, but you can modify the Dockerfile to run as a non-root user
212+
- Database volume is isolated from the host filesystem
213+
- Health checks are available for monitoring
193214

194-
3. Restart the container:
195-
```bash
196-
docker-compose up --build
197-
```
215+
### Backup Strategy
198216

199-
### Permission Issues
217+
1. **Regular backups**: Set up automated backups of the `scim_database` volume
218+
2. **Test restores**: Regularly test backup restoration procedures
219+
3. **Multiple locations**: Store backups in multiple locations
200220

201-
If you encounter permission issues with mounted volumes, ensure the current user has write permissions to the mounted directories.
221+
### Monitoring
202222

203-
## Production Considerations
223+
- Use the health check endpoints for monitoring
224+
- Monitor container logs for errors
225+
- Set up alerts for database connectivity issues
204226

205-
For production deployment:
227+
### Scaling
206228

207-
1. Use environment-specific configuration
208-
2. Consider using PostgreSQL instead of SQLite
209-
3. Set up proper logging and monitoring
210-
4. Configure SSL/TLS termination
211-
5. Use secrets management for API keys
212-
6. Monitor health check metrics
213-
7. Set up alerting for health check failures
229+
- The current setup is designed for single-instance deployment
230+
- For multi-instance deployment, consider using an external database (PostgreSQL, MySQL)
231+
- Update the `DATABASE_URL` environment variable to point to your external database

Dockerfile

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -26,13 +26,15 @@ RUN pip install --no-cache-dir -r requirements.txt
2626
# Copy application code
2727
COPY . .
2828

29-
# Create logs directory
30-
RUN mkdir -p logs
29+
# Create logs and database directories and ensure proper permissions
30+
RUN mkdir -p logs db && chmod 755 logs db
3131

32-
# Create non-root user for security
32+
# Make startup script executable
33+
RUN chmod +x start.sh
34+
35+
# Create non-root user for security (but allow running as root if needed)
3336
RUN groupadd -r scim && useradd -r -g scim scim
3437
RUN chown -R scim:scim /app
35-
USER scim
3638

3739
# Expose port
3840
EXPOSE 7001
@@ -42,4 +44,4 @@ HEALTHCHECK --interval=30s --timeout=10s --start-period=60s --retries=5 \
4244
CMD curl -f http://localhost:7001/healthz || exit 1
4345

4446
# Default command
45-
CMD ["uvicorn", "scim_server.main:app", "--host", "0.0.0.0", "--port", "7001"]
47+
CMD ["./start.sh"]

docker-compose.yml

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -11,14 +11,14 @@ services:
1111
environment:
1212
- PYTHONPATH=/app
1313
- LOG_LEVEL=info
14+
- DATABASE_URL=sqlite:////app/db/scim.db
1415
volumes:
15-
# Mount database for persistence
16-
- ./scim.db:/app/scim.db
16+
# Use Docker volume for database persistence
17+
- scim_database:/app/db
1718
# Mount logs directory for external access
1819
- ./logs:/app/logs
19-
# Mount test database if needed
20-
- ./test_scim.db:/app/test_scim.db
2120
restart: unless-stopped
21+
user: "0:0" # Run as root to avoid permission issues
2222
healthcheck:
2323
test: ["CMD", "curl", "-f", "http://localhost:7001/healthz"]
2424
interval: 30s
@@ -47,5 +47,6 @@ networks:
4747
scim-network:
4848
driver: bridge
4949

50-
# volumes:
51-
# postgres_data:
50+
volumes:
51+
scim_database:
52+
driver: local

frontend/static/index.html

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -257,6 +257,47 @@ <h3>Export Server Data</h3>
257257
copyToClipboard(scimUrl);
258258
}
259259

260+
function copyServerId(serverId) {
261+
copyToClipboard(serverId);
262+
}
263+
264+
function copyServerBaseUrl(serverId) {
265+
const protocol = window.location.protocol;
266+
const host = window.location.host;
267+
const baseUrl = `${protocol}//${host}/scim-identifier/${serverId}/scim/v2`;
268+
copyToClipboard(baseUrl);
269+
}
270+
271+
function copyCurlExample(serverId) {
272+
const protocol = window.location.protocol;
273+
const host = window.location.host;
274+
const baseUrl = `${protocol}//${host}/scim-identifier/${serverId}/scim/v2`;
275+
276+
// Get the API key from the page (if available)
277+
const apiKey = getApiKey();
278+
const authHeader = apiKey ? `-H "Authorization: ${apiKey}"` : '';
279+
280+
const curlExample = `# Test SCIM Server: ${serverId}
281+
# Base URL: ${baseUrl}
282+
283+
# Test Users endpoint
284+
curl -X GET "${baseUrl}/Users" -H "Accept: application/scim+json" -H "Content-Type: application/scim+json" ${authHeader}
285+
286+
# Test Groups endpoint
287+
curl -X GET "${baseUrl}/Groups" -H "Accept: application/scim+json" -H "Content-Type: application/scim+json" ${authHeader}
288+
289+
# Test ServiceProviderConfig
290+
curl -X GET "${baseUrl}/ServiceProviderConfig" -H "Accept: application/scim+json" -H "Content-Type: application/scim+json" ${authHeader}
291+
292+
# Test ResourceTypes
293+
curl -X GET "${baseUrl}/ResourceTypes" -H "Accept: application/scim+json" -H "Content-Type: application/scim+json" ${authHeader}
294+
295+
# Test Schemas
296+
curl -X GET "${baseUrl}/Schemas" -H "Accept: application/scim+json" -H "Content-Type: application/scim+json" ${authHeader}`;
297+
298+
copyToClipboard(curlExample);
299+
}
300+
260301
async function makeApiCall(endpoint, options = {}) {
261302
const apiKey = getApiKey();
262303
const headers = {
@@ -308,8 +349,11 @@ <h3>Export Server Data</h3>
308349
<div class="server-card">
309350
<div style="display: flex; align-items: center; gap: 10px; margin-bottom: 10px;">
310351
<div class="server-id">${server.server_id}</div>
352+
<button class="btn" onclick="copyServerId('${server.server_id}')" style="padding: 5px 10px; font-size: 12px;">Copy Server ID</button>
353+
<button class="btn" onclick="copyServerBaseUrl('${server.server_id}')" style="padding: 5px 10px; font-size: 12px;">Copy Server URL</button>
311354
<button class="btn" onclick="copyServerUrl('${server.server_id}', 'Users')" style="padding: 5px 10px; font-size: 12px;">Copy Users URL</button>
312355
<button class="btn" onclick="copyServerUrl('${server.server_id}', 'Groups')" style="padding: 5px 10px; font-size: 12px;">Copy Groups URL</button>
356+
<button class="btn" onclick="copyCurlExample('${server.server_id}')" style="padding: 5px 10px; font-size: 12px;">Copy cURL Example</button>
313357
</div>
314358
${server.app_profile ? `
315359
<div style="margin-bottom: 10px; padding: 10px; background: #f8f9fa; border-radius: 4px; border-left: 4px solid #3498db;">

scim_server/config.py

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,11 @@
1+
import os
2+
from typing import List, Dict, Any
3+
14
class Settings:
25
"""Application settings - all configuration in one place."""
36

47
# Database settings
5-
database_url: str = "sqlite:///./scim.db"
8+
database_url: str = os.getenv("DATABASE_URL", "sqlite:///./scim.db")
69

710
# API settings
811
max_results_per_page: int = 100
@@ -264,6 +267,14 @@ class Settings:
264267
# Relationship distribution settings
265268
cli_max_groups_per_user: int = 6 # Maximum groups a user can belong to
266269
cli_max_entitlements_per_user: int = 8 # Maximum entitlements a user can have
270+
271+
# Sortable fields configuration - Static list of fields that can be used for sorting
272+
# These fields must exist in the database models and be mapped correctly in the CRUD layer
273+
sortable_fields: Dict[str, List[str]] = {
274+
'User': ['userName', 'displayName', 'id', 'created', 'lastModified'],
275+
'Group': ['displayName', 'id', 'created', 'lastModified'],
276+
'Entitlement': ['displayName', 'id', 'created', 'lastModified']
277+
}
267278

268279
# Global settings instance
269280
settings = Settings()

0 commit comments

Comments
 (0)