mirror of
https://github.com/freedbygrace/ActiveDirectoryManager.git
synced 2026-08-24 17:46:52 +00:00
Reorganize infrastructure as code and implement versioning schema
This commit is contained in:
@@ -1,69 +0,0 @@
|
|||||||
name: Docker
|
|
||||||
|
|
||||||
on:
|
|
||||||
push:
|
|
||||||
branches: [ "main" ]
|
|
||||||
tags: [ 'v*.*.*' ]
|
|
||||||
pull_request:
|
|
||||||
branches: [ "main" ]
|
|
||||||
|
|
||||||
env:
|
|
||||||
# Use docker.io for Docker Hub if empty
|
|
||||||
REGISTRY: docker.io
|
|
||||||
# github.repository as <account>/<repo>
|
|
||||||
IMAGE_NAME: ${{ github.repository }}
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
build:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
permissions:
|
|
||||||
contents: read
|
|
||||||
packages: write
|
|
||||||
# This is needed for token authentication
|
|
||||||
id-token: write
|
|
||||||
|
|
||||||
steps:
|
|
||||||
- name: Checkout repository
|
|
||||||
uses: actions/checkout@v3
|
|
||||||
|
|
||||||
# Workaround: https://github.com/docker/build-push-action/issues/461
|
|
||||||
- name: Setup Docker buildx
|
|
||||||
uses: docker/setup-buildx-action@79abd3f86f79a9d68a23c75a09a9a85889262adf
|
|
||||||
|
|
||||||
# Login against a Docker registry
|
|
||||||
# https://github.com/docker/login-action
|
|
||||||
- name: Log into registry ${{ env.REGISTRY }}
|
|
||||||
if: github.event_name != 'pull_request'
|
|
||||||
uses: docker/login-action@28218f9b04b4f3f62068d7b6ce6ca5b26e35336c
|
|
||||||
with:
|
|
||||||
registry: ${{ env.REGISTRY }}
|
|
||||||
username: ${{ secrets.DOCKERHUB_USERNAME }}
|
|
||||||
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
|
||||||
|
|
||||||
# Extract metadata (tags, labels) for Docker
|
|
||||||
# https://github.com/docker/metadata-action
|
|
||||||
- name: Extract Docker metadata
|
|
||||||
id: meta
|
|
||||||
uses: docker/metadata-action@98669ae865ea3cffbcbaa878cf57c20bbf1c6c38
|
|
||||||
with:
|
|
||||||
images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
|
|
||||||
tags: |
|
|
||||||
type=ref,event=branch
|
|
||||||
type=ref,event=pr
|
|
||||||
type=semver,pattern={{version}}
|
|
||||||
type=semver,pattern={{major}}.{{minor}}
|
|
||||||
type=semver,pattern={{major}}
|
|
||||||
type=sha
|
|
||||||
|
|
||||||
# Build and push Docker image with Buildx
|
|
||||||
# https://github.com/docker/build-push-action
|
|
||||||
- name: Build and push Docker image
|
|
||||||
id: build-and-push
|
|
||||||
uses: docker/build-push-action@ac9327eae2b366085ac7f6a2d02df8aa8ead720a
|
|
||||||
with:
|
|
||||||
context: .
|
|
||||||
push: ${{ github.event_name != 'pull_request' }}
|
|
||||||
tags: ${{ steps.meta.outputs.tags }}
|
|
||||||
labels: ${{ steps.meta.outputs.labels }}
|
|
||||||
cache-from: type=gha
|
|
||||||
cache-to: type=gha,mode=max
|
|
||||||
+7
-3
@@ -53,7 +53,7 @@ This document provides detailed instructions for deploying the Active Directory
|
|||||||
```bash
|
```bash
|
||||||
cp .env.example .env
|
cp .env.example .env
|
||||||
```
|
```
|
||||||
|
|
||||||
Edit the .env file with your specific configuration:
|
Edit the .env file with your specific configuration:
|
||||||
```bash
|
```bash
|
||||||
nano .env
|
nano .env
|
||||||
@@ -62,9 +62,9 @@ This document provides detailed instructions for deploying the Active Directory
|
|||||||
3. **SSL Configuration**
|
3. **SSL Configuration**
|
||||||
|
|
||||||
For production environments, the application is designed to work behind a reverse proxy or load balancer that handles SSL termination.
|
For production environments, the application is designed to work behind a reverse proxy or load balancer that handles SSL termination.
|
||||||
|
|
||||||
If you need to implement SSL directly in your environment, consider:
|
If you need to implement SSL directly in your environment, consider:
|
||||||
|
|
||||||
- Using a reverse proxy like Nginx or Traefik in front of the application
|
- Using a reverse proxy like Nginx or Traefik in front of the application
|
||||||
- Setting up SSL termination at the infrastructure level (e.g., using AWS Application Load Balancer)
|
- Setting up SSL termination at the infrastructure level (e.g., using AWS Application Load Balancer)
|
||||||
- Configuring your cloud provider's SSL management services
|
- Configuring your cloud provider's SSL management services
|
||||||
@@ -391,6 +391,8 @@ For deployment on Microsoft Azure:
|
|||||||
|
|
||||||
Detailed Azure deployment instructions can be found in [AZURE_DEPLOYMENT.md](AZURE_DEPLOYMENT.md).
|
Detailed Azure deployment instructions can be found in [AZURE_DEPLOYMENT.md](AZURE_DEPLOYMENT.md).
|
||||||
|
|
||||||
|
For comprehensive Kubernetes deployment instructions for any cloud provider, refer to the [Kubernetes Deployment Guide](docs/kubernetes-deployment.md).
|
||||||
|
|
||||||
### Google Cloud Deployment
|
### Google Cloud Deployment
|
||||||
|
|
||||||
For deployment on Google Cloud Platform:
|
For deployment on Google Cloud Platform:
|
||||||
@@ -411,6 +413,8 @@ For deployment on Google Cloud Platform:
|
|||||||
|
|
||||||
Detailed GCP deployment instructions can be found in [GCP_DEPLOYMENT.md](GCP_DEPLOYMENT.md).
|
Detailed GCP deployment instructions can be found in [GCP_DEPLOYMENT.md](GCP_DEPLOYMENT.md).
|
||||||
|
|
||||||
|
For comprehensive Kubernetes deployment instructions for any cloud provider, refer to the [Kubernetes Deployment Guide](docs/kubernetes-deployment.md).
|
||||||
|
|
||||||
## Production Best Practices
|
## Production Best Practices
|
||||||
|
|
||||||
### Security Considerations
|
### Security Considerations
|
||||||
|
|||||||
@@ -23,6 +23,9 @@ The Active Directory Management Platform provides the following key features:
|
|||||||
|
|
||||||
### Core Functionality
|
### Core Functionality
|
||||||
- **User Management**: Create, read, update, and delete Active Directory users with comprehensive attribute support
|
- **User Management**: Create, read, update, and delete Active Directory users with comprehensive attribute support
|
||||||
|
- Password reset with policy validation options
|
||||||
|
- Account enabling/disabling
|
||||||
|
- Bulk account management operations
|
||||||
- **Group Management**: Manage security and distribution groups, including nested group structures
|
- **Group Management**: Manage security and distribution groups, including nested group structures
|
||||||
- **Organizational Unit (OU) Management**: Create and manage the hierarchical OU structure
|
- **Organizational Unit (OU) Management**: Create and manage the hierarchical OU structure
|
||||||
- **Computer Management**: Manage computer accounts with detailed property configuration
|
- **Computer Management**: Manage computer accounts with detailed property configuration
|
||||||
@@ -76,6 +79,8 @@ The Active Directory Management Platform provides the following key features:
|
|||||||
|
|
||||||
### DevOps
|
### DevOps
|
||||||
- **Docker**: Containerization platform for consistent deployment
|
- **Docker**: Containerization platform for consistent deployment
|
||||||
|
- **Kubernetes**: Container orchestration for scalable deployments
|
||||||
|
- **Infrastructure as Code (IaC)**: Deployment configurations for Docker and Kubernetes
|
||||||
|
|
||||||
## Architecture
|
## Architecture
|
||||||
|
|
||||||
@@ -111,8 +116,8 @@ The application follows a modern web architecture with clear separation of conce
|
|||||||
|
|
||||||
3. Create a .env file from the example:
|
3. Create a .env file from the example:
|
||||||
```bash
|
```bash
|
||||||
cp .env.example .env
|
cp iac/docker/.env.example iac/docker/.env
|
||||||
# Edit .env with your configuration
|
# Edit iac/docker/.env with your configuration
|
||||||
```
|
```
|
||||||
|
|
||||||
4. Set up the database:
|
4. Set up the database:
|
||||||
@@ -142,8 +147,8 @@ The application follows a modern web architecture with clear separation of conce
|
|||||||
|
|
||||||
2. Create a .env file from the example:
|
2. Create a .env file from the example:
|
||||||
```bash
|
```bash
|
||||||
cp .env.example .env
|
cp iac/docker/.env.example iac/docker/.env
|
||||||
# Edit .env with your production configuration
|
# Edit iac/docker/.env with your production configuration
|
||||||
```
|
```
|
||||||
|
|
||||||
3. Set up environment variables for production:
|
3. Set up environment variables for production:
|
||||||
@@ -155,6 +160,7 @@ The application follows a modern web architecture with clear separation of conce
|
|||||||
|
|
||||||
4. Start the application stack:
|
4. Start the application stack:
|
||||||
```bash
|
```bash
|
||||||
|
cd iac/docker
|
||||||
docker-compose up -d
|
docker-compose up -d
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -187,6 +193,10 @@ The application is also available as a pre-built Docker image:
|
|||||||
|
|
||||||
For manual deployment instructions, refer to the [Deployment Guide](DEPLOYMENT.md).
|
For manual deployment instructions, refer to the [Deployment Guide](DEPLOYMENT.md).
|
||||||
|
|
||||||
|
#### Kubernetes Deployment
|
||||||
|
|
||||||
|
For Kubernetes deployment instructions, refer to the [Kubernetes Deployment Guide](docs/kubernetes-deployment.md).
|
||||||
|
|
||||||
## API Documentation
|
## API Documentation
|
||||||
|
|
||||||
The API is thoroughly documented using the OpenAPI specification (Swagger):
|
The API is thoroughly documented using the OpenAPI specification (Swagger):
|
||||||
@@ -202,6 +212,10 @@ The API is thoroughly documented using the OpenAPI specification (Swagger):
|
|||||||
- **Response Format**: Consistent JSON structure with appropriate status codes
|
- **Response Format**: Consistent JSON structure with appropriate status codes
|
||||||
- **Error Handling**: Descriptive error messages and appropriate HTTP status codes
|
- **Error Handling**: Descriptive error messages and appropriate HTTP status codes
|
||||||
|
|
||||||
|
### API Examples
|
||||||
|
|
||||||
|
For examples of using the API, including the password reset and account management endpoints, refer to the [API Examples Guide](docs/api-examples.md).
|
||||||
|
|
||||||
### Filterable Endpoints
|
### Filterable Endpoints
|
||||||
|
|
||||||
All list endpoints support filtering with a flexible query syntax:
|
All list endpoints support filtering with a flexible query syntax:
|
||||||
|
|||||||
@@ -0,0 +1,319 @@
|
|||||||
|
# API Examples
|
||||||
|
|
||||||
|
This document provides examples of using the Active Directory Management API, including the new password reset and account management endpoints.
|
||||||
|
|
||||||
|
## Table of Contents
|
||||||
|
|
||||||
|
- [Authentication](#authentication)
|
||||||
|
- [User Management](#user-management)
|
||||||
|
- [Password Management](#password-management)
|
||||||
|
- [Account Status Management](#account-status-management)
|
||||||
|
- [Group Management](#group-management)
|
||||||
|
- [Bulk Operations](#bulk-operations)
|
||||||
|
- [Error Handling](#error-handling)
|
||||||
|
|
||||||
|
## Authentication
|
||||||
|
|
||||||
|
### Login
|
||||||
|
|
||||||
|
```bash
|
||||||
|
curl -X POST http://localhost:5000/api/auth/login \
|
||||||
|
-H "Content-Type: application/json" \
|
||||||
|
-d '{
|
||||||
|
"username": "admin",
|
||||||
|
"password": "your-password"
|
||||||
|
}'
|
||||||
|
```
|
||||||
|
|
||||||
|
Response:
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
|
||||||
|
"user": {
|
||||||
|
"id": 1,
|
||||||
|
"username": "admin",
|
||||||
|
"email": "admin@example.com",
|
||||||
|
"fullName": "System Administrator",
|
||||||
|
"role": "admin"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Using the Token
|
||||||
|
|
||||||
|
For all subsequent requests, include the token in the Authorization header:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
curl -X GET http://localhost:5000/api/users \
|
||||||
|
-H "Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
|
||||||
|
```
|
||||||
|
|
||||||
|
## User Management
|
||||||
|
|
||||||
|
### Get All Users
|
||||||
|
|
||||||
|
```bash
|
||||||
|
curl -X GET http://localhost:5000/api/connections/1/ad-users \
|
||||||
|
-H "Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
|
||||||
|
```
|
||||||
|
|
||||||
|
### Get User by ObjectGUID
|
||||||
|
|
||||||
|
```bash
|
||||||
|
curl -X GET http://localhost:5000/api/connections/1/ad-users/a1b2c3d4-e5f6-7890-abcd-ef1234567890 \
|
||||||
|
-H "Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
|
||||||
|
```
|
||||||
|
|
||||||
|
### Create User
|
||||||
|
|
||||||
|
```bash
|
||||||
|
curl -X POST http://localhost:5000/api/connections/1/ad-users \
|
||||||
|
-H "Content-Type: application/json" \
|
||||||
|
-H "Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..." \
|
||||||
|
-d '{
|
||||||
|
"sAMAccountName": "jdoe",
|
||||||
|
"givenName": "John",
|
||||||
|
"sn": "Doe",
|
||||||
|
"displayName": "John Doe",
|
||||||
|
"mail": "jdoe@example.com",
|
||||||
|
"userPrincipalName": "jdoe@example.com",
|
||||||
|
"parentOU": "OU=Users,DC=example,DC=com",
|
||||||
|
"password": "SecurePassword123!",
|
||||||
|
"enabled": true
|
||||||
|
}'
|
||||||
|
```
|
||||||
|
|
||||||
|
### Update User
|
||||||
|
|
||||||
|
```bash
|
||||||
|
curl -X PATCH http://localhost:5000/api/connections/1/ad-users/a1b2c3d4-e5f6-7890-abcd-ef1234567890 \
|
||||||
|
-H "Content-Type: application/json" \
|
||||||
|
-H "Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..." \
|
||||||
|
-d '{
|
||||||
|
"displayName": "John A. Doe",
|
||||||
|
"mail": "john.doe@example.com",
|
||||||
|
"telephoneNumber": "+1 (555) 123-4567"
|
||||||
|
}'
|
||||||
|
```
|
||||||
|
|
||||||
|
### Delete User
|
||||||
|
|
||||||
|
```bash
|
||||||
|
curl -X DELETE http://localhost:5000/api/connections/1/ad-users/a1b2c3d4-e5f6-7890-abcd-ef1234567890 \
|
||||||
|
-H "Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
|
||||||
|
```
|
||||||
|
|
||||||
|
## Password Management
|
||||||
|
|
||||||
|
### Reset User Password
|
||||||
|
|
||||||
|
```bash
|
||||||
|
curl -X POST http://localhost:5000/api/connections/1/reset-password \
|
||||||
|
-H "Content-Type: application/json" \
|
||||||
|
-H "Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..." \
|
||||||
|
-d '{
|
||||||
|
"userObjectGUID": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
|
||||||
|
"newPassword": "NewSecurePassword456!",
|
||||||
|
"skipValidation": false,
|
||||||
|
"requirePasswordChangeAtNextLogon": true
|
||||||
|
}'
|
||||||
|
```
|
||||||
|
|
||||||
|
Response:
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"success": true,
|
||||||
|
"message": "Password reset successful for user with GUID a1b2c3d4-e5f6-7890-abcd-ef1234567890"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Reset Password with Skip Validation
|
||||||
|
|
||||||
|
For scenarios where you need to bypass password policy validation:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
curl -X POST http://localhost:5000/api/connections/1/reset-password \
|
||||||
|
-H "Content-Type: application/json" \
|
||||||
|
-H "Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..." \
|
||||||
|
-d '{
|
||||||
|
"userObjectGUID": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
|
||||||
|
"newPassword": "TempPass123",
|
||||||
|
"skipValidation": true,
|
||||||
|
"requirePasswordChangeAtNextLogon": true
|
||||||
|
}'
|
||||||
|
```
|
||||||
|
|
||||||
|
### Reset Password Without Requiring Change at Next Logon
|
||||||
|
|
||||||
|
```bash
|
||||||
|
curl -X POST http://localhost:5000/api/connections/1/reset-password \
|
||||||
|
-H "Content-Type: application/json" \
|
||||||
|
-H "Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..." \
|
||||||
|
-d '{
|
||||||
|
"userObjectGUID": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
|
||||||
|
"newPassword": "NewSecurePassword456!",
|
||||||
|
"requirePasswordChangeAtNextLogon": false
|
||||||
|
}'
|
||||||
|
```
|
||||||
|
|
||||||
|
## Account Status Management
|
||||||
|
|
||||||
|
### Enable User Account
|
||||||
|
|
||||||
|
```bash
|
||||||
|
curl -X POST http://localhost:5000/api/connections/1/enable-user-account \
|
||||||
|
-H "Content-Type: application/json" \
|
||||||
|
-H "Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..." \
|
||||||
|
-d '{
|
||||||
|
"userObjectGUID": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
|
||||||
|
"enabled": true
|
||||||
|
}'
|
||||||
|
```
|
||||||
|
|
||||||
|
Response:
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"success": true,
|
||||||
|
"message": "User account enabled successfully for user with GUID a1b2c3d4-e5f6-7890-abcd-ef1234567890"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Disable User Account
|
||||||
|
|
||||||
|
```bash
|
||||||
|
curl -X POST http://localhost:5000/api/connections/1/enable-user-account \
|
||||||
|
-H "Content-Type: application/json" \
|
||||||
|
-H "Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..." \
|
||||||
|
-d '{
|
||||||
|
"userObjectGUID": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
|
||||||
|
"enabled": false
|
||||||
|
}'
|
||||||
|
```
|
||||||
|
|
||||||
|
Response:
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"success": true,
|
||||||
|
"message": "User account disabled successfully for user with GUID a1b2c3d4-e5f6-7890-abcd-ef1234567890"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Bulk Enable User Accounts
|
||||||
|
|
||||||
|
```bash
|
||||||
|
curl -X POST http://localhost:5000/api/connections/1/bulk-enable-user-accounts \
|
||||||
|
-H "Content-Type: application/json" \
|
||||||
|
-H "Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..." \
|
||||||
|
-d '{
|
||||||
|
"userDNs": [
|
||||||
|
"CN=John Doe,OU=Users,DC=example,DC=com",
|
||||||
|
"CN=Jane Smith,OU=Users,DC=example,DC=com",
|
||||||
|
"CN=Bob Johnson,OU=Users,DC=example,DC=com"
|
||||||
|
],
|
||||||
|
"enabled": true
|
||||||
|
}'
|
||||||
|
```
|
||||||
|
|
||||||
|
Response:
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"success": [
|
||||||
|
"CN=John Doe,OU=Users,DC=example,DC=com",
|
||||||
|
"CN=Jane Smith,OU=Users,DC=example,DC=com",
|
||||||
|
"CN=Bob Johnson,OU=Users,DC=example,DC=com"
|
||||||
|
],
|
||||||
|
"failed": []
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Bulk Disable User Accounts
|
||||||
|
|
||||||
|
```bash
|
||||||
|
curl -X POST http://localhost:5000/api/connections/1/bulk-enable-user-accounts \
|
||||||
|
-H "Content-Type: application/json" \
|
||||||
|
-H "Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..." \
|
||||||
|
-d '{
|
||||||
|
"userDNs": [
|
||||||
|
"CN=John Doe,OU=Users,DC=example,DC=com",
|
||||||
|
"CN=Jane Smith,OU=Users,DC=example,DC=com",
|
||||||
|
"CN=Bob Johnson,OU=Users,DC=example,DC=com"
|
||||||
|
],
|
||||||
|
"enabled": false
|
||||||
|
}'
|
||||||
|
```
|
||||||
|
|
||||||
|
## Group Management
|
||||||
|
|
||||||
|
### Add User to Group
|
||||||
|
|
||||||
|
```bash
|
||||||
|
curl -X POST http://localhost:5000/api/connections/1/add-to-group \
|
||||||
|
-H "Content-Type: application/json" \
|
||||||
|
-H "Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..." \
|
||||||
|
-d '{
|
||||||
|
"objectGUID": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
|
||||||
|
"groupObjectGUID": "g1h2i3j4-k5l6-7890-mnop-qr1234567890",
|
||||||
|
"objectType": "user"
|
||||||
|
}'
|
||||||
|
```
|
||||||
|
|
||||||
|
### Remove User from Group
|
||||||
|
|
||||||
|
```bash
|
||||||
|
curl -X POST http://localhost:5000/api/connections/1/remove-from-group \
|
||||||
|
-H "Content-Type: application/json" \
|
||||||
|
-H "Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..." \
|
||||||
|
-d '{
|
||||||
|
"objectGUID": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
|
||||||
|
"groupObjectGUID": "g1h2i3j4-k5l6-7890-mnop-qr1234567890",
|
||||||
|
"objectType": "user"
|
||||||
|
}'
|
||||||
|
```
|
||||||
|
|
||||||
|
## Error Handling
|
||||||
|
|
||||||
|
### Invalid Request
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"errors": [
|
||||||
|
{
|
||||||
|
"code": "invalid_type",
|
||||||
|
"expected": "string",
|
||||||
|
"received": "undefined",
|
||||||
|
"path": ["userObjectGUID"],
|
||||||
|
"message": "User ObjectGUID is required"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### User Not Found
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"message": "User not found"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Permission Denied
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"message": "You do not have permission to perform this action"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### LDAP Operation Failed
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"message": "Failed to reset password",
|
||||||
|
"error": "LDAP operation failed: Constraint violation"
|
||||||
|
}
|
||||||
|
```
|
||||||
@@ -0,0 +1,316 @@
|
|||||||
|
# Deployment Guide
|
||||||
|
|
||||||
|
This guide provides instructions for deploying the Active Directory Management application using Docker, Docker Compose, and Kubernetes.
|
||||||
|
|
||||||
|
## Table of Contents
|
||||||
|
|
||||||
|
- [Docker Deployment](#docker-deployment)
|
||||||
|
- [Building the Docker Image](#building-the-docker-image)
|
||||||
|
- [Running with Docker](#running-with-docker)
|
||||||
|
- [Environment Variables](#environment-variables)
|
||||||
|
- [Docker Compose Deployment](#docker-compose-deployment)
|
||||||
|
- [Configuration](#configuration)
|
||||||
|
- [Starting the Services](#starting-the-services)
|
||||||
|
- [Stopping the Services](#stopping-the-services)
|
||||||
|
- [Kubernetes Deployment](#kubernetes-deployment)
|
||||||
|
- [Prerequisites](#prerequisites)
|
||||||
|
- [Configuration](#kubernetes-configuration)
|
||||||
|
- [Deployment](#deployment)
|
||||||
|
- [Accessing the Application](#accessing-the-application)
|
||||||
|
- [Scaling](#scaling)
|
||||||
|
- [Updating](#updating)
|
||||||
|
- [Monitoring](#monitoring)
|
||||||
|
- [Production Considerations](#production-considerations)
|
||||||
|
- [Security](#security)
|
||||||
|
- [Backups](#backups)
|
||||||
|
- [High Availability](#high-availability)
|
||||||
|
|
||||||
|
## Docker Deployment
|
||||||
|
|
||||||
|
### Building the Docker Image
|
||||||
|
|
||||||
|
To build the Docker image using the provided build scripts:
|
||||||
|
|
||||||
|
#### Linux/macOS:
|
||||||
|
```bash
|
||||||
|
# Navigate to the iac/docker directory
|
||||||
|
cd iac/docker
|
||||||
|
|
||||||
|
# Make the script executable
|
||||||
|
chmod +x build.sh
|
||||||
|
|
||||||
|
# Build the image with default settings
|
||||||
|
./build.sh
|
||||||
|
|
||||||
|
# Build with custom tag
|
||||||
|
./build.sh --tag v1.0.0
|
||||||
|
|
||||||
|
# Build and push to a registry
|
||||||
|
./build.sh --registry your-registry.com --tag v1.0.0 --push
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Windows:
|
||||||
|
```powershell
|
||||||
|
# Navigate to the iac/docker directory
|
||||||
|
cd iac\docker
|
||||||
|
|
||||||
|
# Build the image with default settings
|
||||||
|
.\build.ps1
|
||||||
|
|
||||||
|
# Build with custom tag
|
||||||
|
.\build.ps1 -tag v1.0.0
|
||||||
|
|
||||||
|
# Build and push to a registry
|
||||||
|
.\build.ps1 -registry your-registry.com -tag v1.0.0 -push
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Manually:
|
||||||
|
```bash
|
||||||
|
# Navigate to the project root
|
||||||
|
cd /path/to/project
|
||||||
|
|
||||||
|
# Build the image
|
||||||
|
docker build -t ad-management:latest -f iac/docker/Dockerfile .
|
||||||
|
```
|
||||||
|
|
||||||
|
### Running with Docker
|
||||||
|
|
||||||
|
To run the application with Docker:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
docker run -d --name ad-management \
|
||||||
|
-p 5000:5000 \
|
||||||
|
-e NODE_ENV=production \
|
||||||
|
-e POSTGRES_HOST=your-postgres-host \
|
||||||
|
-e POSTGRES_PORT=5432 \
|
||||||
|
-e POSTGRES_DB=admgr \
|
||||||
|
-e POSTGRES_USER=postgres \
|
||||||
|
-e POSTGRES_PASSWORD=your-password \
|
||||||
|
-e REDIS_HOST=your-redis-host \
|
||||||
|
-e REDIS_PORT=6379 \
|
||||||
|
-e JWT_SECRET=your-jwt-secret \
|
||||||
|
-e SESSION_SECRET=your-session-secret \
|
||||||
|
ad-management:latest
|
||||||
|
```
|
||||||
|
|
||||||
|
### Environment Variables
|
||||||
|
|
||||||
|
The application uses the following environment variables:
|
||||||
|
|
||||||
|
| Variable | Description | Default |
|
||||||
|
|----------|-------------|---------|
|
||||||
|
| `NODE_ENV` | Environment mode | `development` |
|
||||||
|
| `PORT` | Port to run the server on | `5000` |
|
||||||
|
| `BASE_URL` | Base URL for the application | `http://localhost:5000` |
|
||||||
|
| `POSTGRES_HOST` | PostgreSQL host | `localhost` |
|
||||||
|
| `POSTGRES_PORT` | PostgreSQL port | `5432` |
|
||||||
|
| `POSTGRES_DB` | PostgreSQL database name | `admgr` |
|
||||||
|
| `POSTGRES_USER` | PostgreSQL username | `postgres` |
|
||||||
|
| `POSTGRES_PASSWORD` | PostgreSQL password | - |
|
||||||
|
| `REDIS_HOST` | Redis host | `localhost` |
|
||||||
|
| `REDIS_PORT` | Redis port | `6379` |
|
||||||
|
| `JWT_SECRET` | Secret for JWT tokens | - |
|
||||||
|
| `SESSION_SECRET` | Secret for session cookies | - |
|
||||||
|
| `DEFAULT_ADMIN_USERNAME` | Default admin username | `admin` |
|
||||||
|
| `DEFAULT_ADMIN_PASSWORD` | Default admin password | - |
|
||||||
|
| `DEFAULT_ADMIN_EMAIL` | Default admin email | - |
|
||||||
|
| `DEFAULT_ADMIN_FULLNAME` | Default admin full name | `System Administrator` |
|
||||||
|
| `DISABLE_REGISTRATION` | Disable user registration | `false` |
|
||||||
|
|
||||||
|
## Docker Compose Deployment
|
||||||
|
|
||||||
|
### Configuration
|
||||||
|
|
||||||
|
The application includes a `docker-compose.yml` file for easy deployment. You can customize the environment variables by creating or modifying the `.env` file in the `iac/docker` directory.
|
||||||
|
|
||||||
|
Example `.env` file:
|
||||||
|
|
||||||
|
```
|
||||||
|
NODE_ENV=production
|
||||||
|
PORT=5000
|
||||||
|
BASE_URL=http://localhost:5000
|
||||||
|
POSTGRES_HOST=postgres
|
||||||
|
POSTGRES_PORT=5432
|
||||||
|
POSTGRES_DB=admgr
|
||||||
|
POSTGRES_USER=postgres
|
||||||
|
POSTGRES_PASSWORD=your-postgres-password
|
||||||
|
REDIS_HOST=redis
|
||||||
|
REDIS_PORT=6379
|
||||||
|
JWT_SECRET=your-jwt-secret
|
||||||
|
SESSION_SECRET=your-session-secret
|
||||||
|
DEFAULT_ADMIN_USERNAME=admin
|
||||||
|
DEFAULT_ADMIN_PASSWORD=your-admin-password
|
||||||
|
DEFAULT_ADMIN_EMAIL=admin@example.com
|
||||||
|
DEFAULT_ADMIN_FULLNAME=System Administrator
|
||||||
|
DISABLE_REGISTRATION=false
|
||||||
|
```
|
||||||
|
|
||||||
|
### Starting the Services
|
||||||
|
|
||||||
|
To start all services:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Navigate to the iac/docker directory
|
||||||
|
cd iac/docker
|
||||||
|
|
||||||
|
# Start the application stack
|
||||||
|
docker-compose up -d
|
||||||
|
```
|
||||||
|
|
||||||
|
This will start the application, PostgreSQL, and Redis containers.
|
||||||
|
|
||||||
|
### Stopping the Services
|
||||||
|
|
||||||
|
To stop all services:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Navigate to the iac/docker directory
|
||||||
|
cd iac/docker
|
||||||
|
|
||||||
|
# Stop the application stack
|
||||||
|
docker-compose down
|
||||||
|
```
|
||||||
|
|
||||||
|
To stop and remove all data volumes:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Navigate to the iac/docker directory
|
||||||
|
cd iac/docker
|
||||||
|
|
||||||
|
# Stop the application stack and remove volumes
|
||||||
|
docker-compose down -v
|
||||||
|
```
|
||||||
|
|
||||||
|
## Kubernetes Deployment
|
||||||
|
|
||||||
|
### Prerequisites
|
||||||
|
|
||||||
|
- Kubernetes cluster (v1.19+)
|
||||||
|
- kubectl configured to communicate with your cluster
|
||||||
|
- [Kustomize](https://kustomize.io/) (v4.0+) or kubectl v1.14+ which includes kustomize
|
||||||
|
- Optional: Ingress controller (e.g., NGINX Ingress Controller)
|
||||||
|
- Optional: cert-manager for TLS certificates
|
||||||
|
|
||||||
|
### Kubernetes Configuration
|
||||||
|
|
||||||
|
The Kubernetes manifests are located in the `iac/kubernetes/` directory. Before deploying, you should customize the following files:
|
||||||
|
|
||||||
|
1. `iac/kubernetes/configmap.yaml`: Update environment variables
|
||||||
|
2. `iac/kubernetes/secrets.yaml`: Update secrets (use base64-encoded values)
|
||||||
|
3. `iac/kubernetes/deployment.yaml`: Update resource limits if needed
|
||||||
|
4. `iac/kubernetes/ingress.yaml`: Update host name and TLS configuration
|
||||||
|
|
||||||
|
### Deployment
|
||||||
|
|
||||||
|
To deploy the application to Kubernetes:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Navigate to the iac/kubernetes directory
|
||||||
|
cd iac/kubernetes
|
||||||
|
|
||||||
|
# Apply all resources
|
||||||
|
kubectl apply -k .
|
||||||
|
|
||||||
|
# Or from anywhere in the project
|
||||||
|
kubectl apply -k iac/kubernetes
|
||||||
|
```
|
||||||
|
|
||||||
|
This will create:
|
||||||
|
- A namespace called `ad-management`
|
||||||
|
- ConfigMap and Secret for environment variables
|
||||||
|
- PostgreSQL StatefulSet with persistent storage
|
||||||
|
- Redis StatefulSet with persistent storage
|
||||||
|
- Application Deployment with 2 replicas
|
||||||
|
- Services for all components
|
||||||
|
- Ingress for external access
|
||||||
|
|
||||||
|
### Accessing the Application
|
||||||
|
|
||||||
|
If you've configured the Ingress, the application will be available at the hostname specified in `kubernetes/ingress.yaml`.
|
||||||
|
|
||||||
|
Without Ingress, you can use port-forwarding to access the application:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
kubectl port-forward -n ad-management svc/ad-management 5000:80
|
||||||
|
```
|
||||||
|
|
||||||
|
Then access the application at http://localhost:5000.
|
||||||
|
|
||||||
|
### Scaling
|
||||||
|
|
||||||
|
To scale the application:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
kubectl scale -n ad-management deployment/ad-management --replicas=3
|
||||||
|
```
|
||||||
|
|
||||||
|
### Updating
|
||||||
|
|
||||||
|
To update the application to a new version:
|
||||||
|
|
||||||
|
1. Build and push the new Docker image
|
||||||
|
2. Update the image tag in `kubernetes/deployment.yaml`
|
||||||
|
3. Apply the changes:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
kubectl apply -k kubernetes/
|
||||||
|
```
|
||||||
|
|
||||||
|
Or use kubectl set image:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
kubectl set image -n ad-management deployment/ad-management ad-management=ad-management:new-tag
|
||||||
|
```
|
||||||
|
|
||||||
|
### Monitoring
|
||||||
|
|
||||||
|
You can monitor the application using:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Check pod status
|
||||||
|
kubectl get pods -n ad-management
|
||||||
|
|
||||||
|
# View logs
|
||||||
|
kubectl logs -n ad-management deployment/ad-management
|
||||||
|
|
||||||
|
# Describe deployment
|
||||||
|
kubectl describe deployment -n ad-management ad-management
|
||||||
|
```
|
||||||
|
|
||||||
|
## Production Considerations
|
||||||
|
|
||||||
|
### Security
|
||||||
|
|
||||||
|
For production deployments:
|
||||||
|
|
||||||
|
1. Use strong, unique passwords for all secrets
|
||||||
|
2. Enable TLS for all connections
|
||||||
|
3. Use network policies to restrict traffic between components
|
||||||
|
4. Set up proper RBAC for Kubernetes resources
|
||||||
|
5. Regularly update all components and dependencies
|
||||||
|
6. Consider using a secrets management solution like HashiCorp Vault
|
||||||
|
|
||||||
|
### Backups
|
||||||
|
|
||||||
|
Set up regular backups for:
|
||||||
|
|
||||||
|
1. PostgreSQL database
|
||||||
|
2. Redis data (if persistence is enabled)
|
||||||
|
3. Application configuration
|
||||||
|
|
||||||
|
Example PostgreSQL backup:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
kubectl exec -n ad-management postgres-0 -- pg_dump -U postgres admgr > backup.sql
|
||||||
|
```
|
||||||
|
|
||||||
|
### High Availability
|
||||||
|
|
||||||
|
For high availability:
|
||||||
|
|
||||||
|
1. Run multiple replicas of the application
|
||||||
|
2. Use a PostgreSQL cluster with replication
|
||||||
|
3. Configure Redis with replication or cluster mode
|
||||||
|
4. Deploy across multiple availability zones
|
||||||
|
5. Use a load balancer or ingress controller with multiple backends
|
||||||
|
6. Implement proper health checks and readiness probes
|
||||||
@@ -0,0 +1,324 @@
|
|||||||
|
# Kubernetes Deployment Guide
|
||||||
|
|
||||||
|
This guide provides detailed instructions for deploying the Active Directory Management application on Kubernetes.
|
||||||
|
|
||||||
|
## Prerequisites
|
||||||
|
|
||||||
|
- Kubernetes cluster (v1.19+)
|
||||||
|
- kubectl configured to communicate with your cluster
|
||||||
|
- [Kustomize](https://kustomize.io/) (v4.0+) or kubectl v1.14+ which includes kustomize
|
||||||
|
- Optional: Ingress controller (e.g., NGINX Ingress Controller)
|
||||||
|
- Optional: cert-manager for TLS certificates
|
||||||
|
|
||||||
|
## Deployment Architecture
|
||||||
|
|
||||||
|
The Kubernetes deployment consists of:
|
||||||
|
|
||||||
|
- **Application Deployment**: The main application with multiple replicas
|
||||||
|
- **PostgreSQL StatefulSet**: Database with persistent storage
|
||||||
|
- **Redis StatefulSet**: Cache and session storage with persistent storage
|
||||||
|
- **Services**: For internal communication between components
|
||||||
|
- **Ingress**: For external access to the application
|
||||||
|
- **ConfigMap and Secrets**: For configuration and sensitive data
|
||||||
|
|
||||||
|
All Kubernetes manifests are located in the `iac/kubernetes/` directory.
|
||||||
|
|
||||||
|
## Step-by-Step Deployment
|
||||||
|
|
||||||
|
### 1. Customize Configuration
|
||||||
|
|
||||||
|
Before deploying, customize the configuration files in the `iac/kubernetes/` directory:
|
||||||
|
|
||||||
|
#### ConfigMap (`iac/kubernetes/configmap.yaml`)
|
||||||
|
|
||||||
|
Update environment variables according to your environment:
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
apiVersion: v1
|
||||||
|
kind: ConfigMap
|
||||||
|
metadata:
|
||||||
|
name: ad-management-config
|
||||||
|
namespace: ad-management
|
||||||
|
data:
|
||||||
|
NODE_ENV: "production"
|
||||||
|
PORT: "5000"
|
||||||
|
BASE_URL: "https://your-domain.com" # Update this
|
||||||
|
DEFAULT_ADMIN_USERNAME: "admin"
|
||||||
|
DEFAULT_ADMIN_FULLNAME: "System Administrator"
|
||||||
|
DISABLE_REGISTRATION: "false"
|
||||||
|
POSTGRES_DB: "admgr"
|
||||||
|
POSTGRES_USER: "postgres"
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Secrets (`kubernetes/secrets.yaml`)
|
||||||
|
|
||||||
|
Update the secrets with your own base64-encoded values:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Generate base64-encoded secrets
|
||||||
|
echo -n "your-jwt-secret" | base64
|
||||||
|
echo -n "your-session-secret" | base64
|
||||||
|
echo -n "your-admin-password" | base64
|
||||||
|
echo -n "admin@your-domain.com" | base64
|
||||||
|
echo -n "your-postgres-password" | base64
|
||||||
|
```
|
||||||
|
|
||||||
|
Then update `iac/kubernetes/secrets.yaml`:
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
apiVersion: v1
|
||||||
|
kind: Secret
|
||||||
|
metadata:
|
||||||
|
name: ad-management-secrets
|
||||||
|
namespace: ad-management
|
||||||
|
type: Opaque
|
||||||
|
data:
|
||||||
|
JWT_SECRET: "base64-encoded-jwt-secret"
|
||||||
|
SESSION_SECRET: "base64-encoded-session-secret"
|
||||||
|
DEFAULT_ADMIN_PASSWORD: "base64-encoded-admin-password"
|
||||||
|
DEFAULT_ADMIN_EMAIL: "base64-encoded-admin-email"
|
||||||
|
POSTGRES_PASSWORD: "base64-encoded-postgres-password"
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Ingress (`iac/kubernetes/ingress.yaml`)
|
||||||
|
|
||||||
|
Update the hostname and TLS configuration:
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
apiVersion: networking.k8s.io/v1
|
||||||
|
kind: Ingress
|
||||||
|
metadata:
|
||||||
|
name: ad-management-ingress
|
||||||
|
namespace: ad-management
|
||||||
|
annotations:
|
||||||
|
kubernetes.io/ingress.class: "nginx"
|
||||||
|
cert-manager.io/cluster-issuer: "letsencrypt-prod"
|
||||||
|
nginx.ingress.kubernetes.io/ssl-redirect: "true"
|
||||||
|
spec:
|
||||||
|
tls:
|
||||||
|
- hosts:
|
||||||
|
- your-domain.com # Update this
|
||||||
|
secretName: ad-management-tls
|
||||||
|
rules:
|
||||||
|
- host: your-domain.com # Update this
|
||||||
|
http:
|
||||||
|
paths:
|
||||||
|
- path: /
|
||||||
|
pathType: Prefix
|
||||||
|
backend:
|
||||||
|
service:
|
||||||
|
name: ad-management
|
||||||
|
port:
|
||||||
|
name: http
|
||||||
|
```
|
||||||
|
|
||||||
|
### 2. Deploy the Application
|
||||||
|
|
||||||
|
Deploy all resources using Kustomize:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Navigate to the iac/kubernetes directory
|
||||||
|
cd iac/kubernetes
|
||||||
|
|
||||||
|
# Apply all resources
|
||||||
|
kubectl apply -k .
|
||||||
|
|
||||||
|
# Or from anywhere in the project
|
||||||
|
kubectl apply -k iac/kubernetes
|
||||||
|
```
|
||||||
|
|
||||||
|
### 3. Verify Deployment
|
||||||
|
|
||||||
|
Check that all resources are created and running:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Check namespace
|
||||||
|
kubectl get namespace ad-management
|
||||||
|
|
||||||
|
# Check pods
|
||||||
|
kubectl get pods -n ad-management
|
||||||
|
|
||||||
|
# Check services
|
||||||
|
kubectl get services -n ad-management
|
||||||
|
|
||||||
|
# Check deployments and statefulsets
|
||||||
|
kubectl get deployment,statefulset -n ad-management
|
||||||
|
|
||||||
|
# Check ingress
|
||||||
|
kubectl get ingress -n ad-management
|
||||||
|
```
|
||||||
|
|
||||||
|
### 4. Access the Application
|
||||||
|
|
||||||
|
If you've configured the Ingress, the application will be available at your specified domain.
|
||||||
|
|
||||||
|
Without Ingress, use port-forwarding:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
kubectl port-forward -n ad-management svc/ad-management 5000:80
|
||||||
|
```
|
||||||
|
|
||||||
|
Then access the application at http://localhost:5000.
|
||||||
|
|
||||||
|
## Common Operations
|
||||||
|
|
||||||
|
### Scaling the Application
|
||||||
|
|
||||||
|
To scale the application horizontally:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
kubectl scale -n ad-management deployment/ad-management --replicas=3
|
||||||
|
```
|
||||||
|
|
||||||
|
### Updating the Application
|
||||||
|
|
||||||
|
To update the application to a new version:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Update the image
|
||||||
|
kubectl set image -n ad-management deployment/ad-management ad-management=ad-management:new-tag
|
||||||
|
|
||||||
|
# Check rollout status
|
||||||
|
kubectl rollout status -n ad-management deployment/ad-management
|
||||||
|
```
|
||||||
|
|
||||||
|
### Viewing Logs
|
||||||
|
|
||||||
|
To view application logs:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# View logs from all pods
|
||||||
|
kubectl logs -n ad-management -l app=ad-management
|
||||||
|
|
||||||
|
# View logs from a specific pod
|
||||||
|
kubectl logs -n ad-management pod/ad-management-xxxx-yyyy
|
||||||
|
```
|
||||||
|
|
||||||
|
### Restarting Components
|
||||||
|
|
||||||
|
To restart the application:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
kubectl rollout restart -n ad-management deployment/ad-management
|
||||||
|
```
|
||||||
|
|
||||||
|
To restart PostgreSQL or Redis:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
kubectl rollout restart -n ad-management statefulset/postgres
|
||||||
|
kubectl rollout restart -n ad-management statefulset/redis
|
||||||
|
```
|
||||||
|
|
||||||
|
## Troubleshooting
|
||||||
|
|
||||||
|
### Pod Startup Issues
|
||||||
|
|
||||||
|
If pods are not starting:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Check pod status
|
||||||
|
kubectl get pods -n ad-management
|
||||||
|
|
||||||
|
# Describe the pod for more details
|
||||||
|
kubectl describe pod -n ad-management pod/ad-management-xxxx-yyyy
|
||||||
|
|
||||||
|
# Check container logs
|
||||||
|
kubectl logs -n ad-management pod/ad-management-xxxx-yyyy
|
||||||
|
```
|
||||||
|
|
||||||
|
### Database Connection Issues
|
||||||
|
|
||||||
|
If the application can't connect to the database:
|
||||||
|
|
||||||
|
1. Check if the PostgreSQL pod is running:
|
||||||
|
```bash
|
||||||
|
kubectl get pods -n ad-management -l app=postgres
|
||||||
|
```
|
||||||
|
|
||||||
|
2. Check PostgreSQL logs:
|
||||||
|
```bash
|
||||||
|
kubectl logs -n ad-management pod/postgres-0
|
||||||
|
```
|
||||||
|
|
||||||
|
3. Verify the connection from the application pod:
|
||||||
|
```bash
|
||||||
|
kubectl exec -it -n ad-management pod/ad-management-xxxx-yyyy -- nc -zv postgres 5432
|
||||||
|
```
|
||||||
|
|
||||||
|
### Ingress Issues
|
||||||
|
|
||||||
|
If the Ingress is not working:
|
||||||
|
|
||||||
|
1. Check the Ingress status:
|
||||||
|
```bash
|
||||||
|
kubectl describe ingress -n ad-management ad-management-ingress
|
||||||
|
```
|
||||||
|
|
||||||
|
2. Check the Ingress controller logs:
|
||||||
|
```bash
|
||||||
|
kubectl logs -n ingress-nginx deployment/ingress-nginx-controller
|
||||||
|
```
|
||||||
|
|
||||||
|
## Examples
|
||||||
|
|
||||||
|
### Example: Setting Up TLS with cert-manager
|
||||||
|
|
||||||
|
1. Install cert-manager:
|
||||||
|
```bash
|
||||||
|
kubectl apply -f https://github.com/cert-manager/cert-manager/releases/download/v1.9.1/cert-manager.yaml
|
||||||
|
```
|
||||||
|
|
||||||
|
2. Create a ClusterIssuer for Let's Encrypt:
|
||||||
|
```yaml
|
||||||
|
apiVersion: cert-manager.io/v1
|
||||||
|
kind: ClusterIssuer
|
||||||
|
metadata:
|
||||||
|
name: letsencrypt-prod
|
||||||
|
spec:
|
||||||
|
acme:
|
||||||
|
server: https://acme-v02.api.letsencrypt.org/directory
|
||||||
|
email: your-email@example.com
|
||||||
|
privateKeySecretRef:
|
||||||
|
name: letsencrypt-prod
|
||||||
|
solvers:
|
||||||
|
- http01:
|
||||||
|
ingress:
|
||||||
|
class: nginx
|
||||||
|
```
|
||||||
|
|
||||||
|
3. Apply the ClusterIssuer:
|
||||||
|
```bash
|
||||||
|
kubectl apply -f cluster-issuer.yaml
|
||||||
|
```
|
||||||
|
|
||||||
|
### Example: Setting Up Monitoring with Prometheus and Grafana
|
||||||
|
|
||||||
|
1. Install Prometheus Operator:
|
||||||
|
```bash
|
||||||
|
kubectl apply -f https://github.com/prometheus-operator/kube-prometheus/releases/download/v0.10.0/manifests-0.10.0.tar.gz
|
||||||
|
```
|
||||||
|
|
||||||
|
2. Create a ServiceMonitor for the application:
|
||||||
|
```yaml
|
||||||
|
apiVersion: monitoring.coreos.com/v1
|
||||||
|
kind: ServiceMonitor
|
||||||
|
metadata:
|
||||||
|
name: ad-management
|
||||||
|
namespace: monitoring
|
||||||
|
spec:
|
||||||
|
selector:
|
||||||
|
matchLabels:
|
||||||
|
app: ad-management
|
||||||
|
namespaceSelector:
|
||||||
|
matchNames:
|
||||||
|
- ad-management
|
||||||
|
endpoints:
|
||||||
|
- port: http
|
||||||
|
path: /metrics
|
||||||
|
interval: 15s
|
||||||
|
```
|
||||||
|
|
||||||
|
3. Apply the ServiceMonitor:
|
||||||
|
```bash
|
||||||
|
kubectl apply -f service-monitor.yaml
|
||||||
|
```
|
||||||
+257
@@ -0,0 +1,257 @@
|
|||||||
|
# Infrastructure as Code (IaC)
|
||||||
|
|
||||||
|
This directory contains all the infrastructure as code configurations for deploying the Active Directory Management application.
|
||||||
|
|
||||||
|
## Directory Structure
|
||||||
|
|
||||||
|
- **docker/**: Docker-related files
|
||||||
|
- `Dockerfile`: Multi-stage Docker build file
|
||||||
|
- `docker-compose.yml`: Docker Compose configuration
|
||||||
|
- `build.sh`: Bash script for building and pushing Docker images (Linux/macOS)
|
||||||
|
- `build.ps1`: PowerShell script for building and pushing Docker images (Windows)
|
||||||
|
- `.env`: Environment variables for Docker deployment
|
||||||
|
- `.env.example`: Example environment variables
|
||||||
|
- `.env.production`: Production environment variables
|
||||||
|
|
||||||
|
- **version.txt**: Central version file in yyyy.MM.dd.HHmm format
|
||||||
|
- **update-version.sh**: Bash script to update version.txt (Linux/macOS)
|
||||||
|
- **update-version.ps1**: PowerShell script to update version.txt (Windows)
|
||||||
|
- **update-all.sh**: Comprehensive script to update all version references (Linux/macOS)
|
||||||
|
- **update-all.ps1**: Comprehensive script to update all version references (Windows)
|
||||||
|
|
||||||
|
- **kubernetes/**: Kubernetes manifests
|
||||||
|
- `namespace.yaml`: Namespace definition
|
||||||
|
- `configmap.yaml`: ConfigMap for non-sensitive configuration
|
||||||
|
- `secrets.yaml`: Secrets for sensitive configuration
|
||||||
|
- `postgres.yaml`: PostgreSQL StatefulSet and Service
|
||||||
|
- `redis.yaml`: Redis StatefulSet and Service
|
||||||
|
- `deployment.yaml`: Application Deployment and Service
|
||||||
|
- `ingress.yaml`: Ingress for external access
|
||||||
|
- `kustomization.yaml`: Kustomize configuration
|
||||||
|
|
||||||
|
## Docker
|
||||||
|
|
||||||
|
### Versioning
|
||||||
|
|
||||||
|
The application uses a versioning scheme in the format `yyyy.MM.dd.HHmm` (year, month, day, hour, minute).
|
||||||
|
|
||||||
|
#### Comprehensive Version Update
|
||||||
|
|
||||||
|
To update the version and apply it to all components (recommended):
|
||||||
|
|
||||||
|
On Linux/macOS:
|
||||||
|
```bash
|
||||||
|
# Navigate to the iac directory
|
||||||
|
cd iac
|
||||||
|
|
||||||
|
# Make the script executable
|
||||||
|
chmod +x update-all.sh
|
||||||
|
|
||||||
|
# Update all version references
|
||||||
|
./update-all.sh
|
||||||
|
```
|
||||||
|
|
||||||
|
On Windows:
|
||||||
|
```powershell
|
||||||
|
# Navigate to the iac directory
|
||||||
|
cd iac
|
||||||
|
|
||||||
|
# Update all version references
|
||||||
|
.\update-all.ps1
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Manual Version Update
|
||||||
|
|
||||||
|
To update only the version.txt file:
|
||||||
|
|
||||||
|
On Linux/macOS:
|
||||||
|
```bash
|
||||||
|
# Navigate to the iac directory
|
||||||
|
cd iac
|
||||||
|
|
||||||
|
# Make the script executable
|
||||||
|
chmod +x update-version.sh
|
||||||
|
|
||||||
|
# Update the version
|
||||||
|
./update-version.sh
|
||||||
|
```
|
||||||
|
|
||||||
|
On Windows:
|
||||||
|
```powershell
|
||||||
|
# Navigate to the iac directory
|
||||||
|
cd iac
|
||||||
|
|
||||||
|
# Update the version
|
||||||
|
.\update-version.ps1
|
||||||
|
```
|
||||||
|
|
||||||
|
### Building Docker Images
|
||||||
|
|
||||||
|
#### Using the build scripts
|
||||||
|
|
||||||
|
On Linux/macOS:
|
||||||
|
```bash
|
||||||
|
# Navigate to the iac/docker directory
|
||||||
|
cd iac/docker
|
||||||
|
|
||||||
|
# Make the script executable
|
||||||
|
chmod +x build.sh
|
||||||
|
|
||||||
|
# Build the image with version from version.txt
|
||||||
|
./build.sh
|
||||||
|
|
||||||
|
# Build with custom tag
|
||||||
|
./build.sh --tag 2025.05.21.1430
|
||||||
|
|
||||||
|
# Build and push to a registry
|
||||||
|
./build.sh --registry your-registry.com --push
|
||||||
|
```
|
||||||
|
|
||||||
|
On Windows:
|
||||||
|
```powershell
|
||||||
|
# Navigate to the iac/docker directory
|
||||||
|
cd iac\docker
|
||||||
|
|
||||||
|
# Build the image with version from version.txt
|
||||||
|
.\build.ps1
|
||||||
|
|
||||||
|
# Build with custom tag
|
||||||
|
.\build.ps1 -tag 2025.05.21.1430
|
||||||
|
|
||||||
|
# Build and push to a registry
|
||||||
|
.\build.ps1 -registry your-registry.com -push
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Manually
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Navigate to the project root
|
||||||
|
cd /path/to/project
|
||||||
|
|
||||||
|
# Get the version from version.txt
|
||||||
|
VERSION=$(cat iac/version.txt)
|
||||||
|
|
||||||
|
# Build the image
|
||||||
|
docker build -t ActiveDirectoryManager:$VERSION -f iac/docker/Dockerfile .
|
||||||
|
|
||||||
|
# Tag the image for a registry
|
||||||
|
docker tag ActiveDirectoryManager:$VERSION your-registry.com/ActiveDirectoryManager:$VERSION
|
||||||
|
|
||||||
|
# Push to registry
|
||||||
|
docker push your-registry.com/ActiveDirectoryManager:$VERSION
|
||||||
|
```
|
||||||
|
|
||||||
|
### Running with Docker Compose
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Navigate to the iac/docker directory
|
||||||
|
cd iac/docker
|
||||||
|
|
||||||
|
# Create a .env file from the example if you haven't already
|
||||||
|
cp .env.example .env
|
||||||
|
# Edit the .env file with your configuration
|
||||||
|
|
||||||
|
# Load the version from version.txt
|
||||||
|
source .env.version
|
||||||
|
|
||||||
|
# Start the application stack
|
||||||
|
docker-compose up -d
|
||||||
|
|
||||||
|
# View logs
|
||||||
|
docker-compose logs -f
|
||||||
|
|
||||||
|
# Stop the application stack
|
||||||
|
docker-compose down
|
||||||
|
```
|
||||||
|
|
||||||
|
## Kubernetes
|
||||||
|
|
||||||
|
### Prerequisites
|
||||||
|
|
||||||
|
- Kubernetes cluster (v1.19+)
|
||||||
|
- kubectl configured to communicate with your cluster
|
||||||
|
- Kustomize (v4.0+) or kubectl v1.14+ which includes kustomize
|
||||||
|
|
||||||
|
### Updating Deployment Version
|
||||||
|
|
||||||
|
Before deploying, you should update the Kubernetes deployment to use the current version:
|
||||||
|
|
||||||
|
On Linux/macOS:
|
||||||
|
```bash
|
||||||
|
# Navigate to the iac/kubernetes directory
|
||||||
|
cd iac/kubernetes
|
||||||
|
|
||||||
|
# Make the script executable
|
||||||
|
chmod +x update-deployment-version.sh
|
||||||
|
|
||||||
|
# Update the deployment version
|
||||||
|
./update-deployment-version.sh
|
||||||
|
```
|
||||||
|
|
||||||
|
On Windows:
|
||||||
|
```powershell
|
||||||
|
# Navigate to the iac/kubernetes directory
|
||||||
|
cd iac\kubernetes
|
||||||
|
|
||||||
|
# Update the deployment version
|
||||||
|
.\update-deployment-version.ps1
|
||||||
|
```
|
||||||
|
|
||||||
|
### Deployment
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Navigate to the iac/kubernetes directory
|
||||||
|
cd iac/kubernetes
|
||||||
|
|
||||||
|
# Apply all resources
|
||||||
|
kubectl apply -k .
|
||||||
|
|
||||||
|
# Or from anywhere in the project
|
||||||
|
kubectl apply -k iac/kubernetes
|
||||||
|
```
|
||||||
|
|
||||||
|
### Customization
|
||||||
|
|
||||||
|
To customize the deployment for different environments:
|
||||||
|
|
||||||
|
1. Create a new directory for your environment:
|
||||||
|
```bash
|
||||||
|
mkdir -p iac/kubernetes/environments/production
|
||||||
|
```
|
||||||
|
|
||||||
|
2. Create a kustomization.yaml file that references the base configuration:
|
||||||
|
```yaml
|
||||||
|
apiVersion: kustomize.config.k8s.io/v1beta1
|
||||||
|
kind: Kustomization
|
||||||
|
|
||||||
|
namespace: ad-management-production
|
||||||
|
|
||||||
|
resources:
|
||||||
|
- ../../ # Reference the base configuration
|
||||||
|
|
||||||
|
patches:
|
||||||
|
# Add your patches here
|
||||||
|
```
|
||||||
|
|
||||||
|
3. Apply the environment-specific configuration:
|
||||||
|
```bash
|
||||||
|
kubectl apply -k iac/kubernetes/environments/production
|
||||||
|
```
|
||||||
|
|
||||||
|
## CI/CD Integration
|
||||||
|
|
||||||
|
The Docker build scripts are designed to be used in CI/CD pipelines. Example integration with GitHub Actions:
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
jobs:
|
||||||
|
build:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v3
|
||||||
|
|
||||||
|
- name: Build and push Docker image
|
||||||
|
run: |
|
||||||
|
cd iac/docker
|
||||||
|
chmod +x build.sh
|
||||||
|
./build.sh --registry ghcr.io --tag ${{ github.sha }} --push
|
||||||
|
```
|
||||||
@@ -0,0 +1,21 @@
|
|||||||
|
# Environment Variables for Docker Deployment
|
||||||
|
# Copy from .env.example and customize as needed
|
||||||
|
|
||||||
|
# Database Configuration
|
||||||
|
POSTGRES_USER=admanagement
|
||||||
|
POSTGRES_PASSWORD=change_this_to_a_secure_password
|
||||||
|
POSTGRES_DB=admanagement
|
||||||
|
|
||||||
|
# Application Configuration
|
||||||
|
NODE_ENV=production
|
||||||
|
PORT=5000
|
||||||
|
BASE_URL=http://localhost:5000
|
||||||
|
SESSION_SECRET=change_this_to_a_random_string
|
||||||
|
JWT_SECRET=change_this_to_a_different_random_string
|
||||||
|
|
||||||
|
# Default Admin User Configuration
|
||||||
|
DEFAULT_ADMIN_USERNAME=admin
|
||||||
|
DEFAULT_ADMIN_PASSWORD=change_this_to_a_secure_password
|
||||||
|
DEFAULT_ADMIN_EMAIL=admin@example.com
|
||||||
|
DEFAULT_ADMIN_FULLNAME=System Administrator
|
||||||
|
DISABLE_REGISTRATION=false
|
||||||
@@ -53,4 +53,4 @@ DISABLE_REGISTRATION=false
|
|||||||
# OIDC_USERINFO_URL=https://openidconnect.googleapis.com/v1/userinfo
|
# OIDC_USERINFO_URL=https://openidconnect.googleapis.com/v1/userinfo
|
||||||
# OIDC_CLIENT_ID=your_client_id
|
# OIDC_CLIENT_ID=your_client_id
|
||||||
# OIDC_CLIENT_SECRET=your_client_secret
|
# OIDC_CLIENT_SECRET=your_client_secret
|
||||||
# OIDC_CALLBACK_URL=http://localhost:5000/api/auth/oidc/callback
|
# OIDC_CALLBACK_URL=http://localhost:5000/api/auth/oidc/callback
|
||||||
@@ -22,4 +22,4 @@ SESSION_COOKIE_SECURE=true
|
|||||||
SESSION_COOKIE_HTTPONLY=true
|
SESSION_COOKIE_HTTPONLY=true
|
||||||
|
|
||||||
# API Settings
|
# API Settings
|
||||||
SWAGGER_ENABLED=true
|
SWAGGER_ENABLED=true
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
# This file is used to set the VERSION environment variable for docker-compose
|
||||||
|
# It reads the version from the version.txt file
|
||||||
|
VERSION=$(cat ../version.txt)
|
||||||
@@ -62,4 +62,4 @@ USER appuser
|
|||||||
EXPOSE 5000
|
EXPOSE 5000
|
||||||
|
|
||||||
# Start the application
|
# Start the application
|
||||||
CMD ["node", "dist/server/index.js"]
|
CMD ["node", "dist/server/index.js"]
|
||||||
@@ -0,0 +1,74 @@
|
|||||||
|
# PowerShell script for building Docker images (Windows)
|
||||||
|
param (
|
||||||
|
[string]$tag = "",
|
||||||
|
[string]$registry = "",
|
||||||
|
[switch]$push = $false,
|
||||||
|
[string]$imageName = "ActiveDirectoryManager"
|
||||||
|
)
|
||||||
|
|
||||||
|
# If no tag is provided, use the version from version.txt
|
||||||
|
if (-not $tag) {
|
||||||
|
$versionFile = Join-Path (Split-Path $PSScriptRoot) "version.txt"
|
||||||
|
if (Test-Path $versionFile) {
|
||||||
|
$tag = Get-Content $versionFile -Raw
|
||||||
|
$tag = $tag.Trim()
|
||||||
|
} else {
|
||||||
|
# If version.txt doesn't exist, use current date/time in yyyy.MM.dd.HHmm format
|
||||||
|
$tag = Get-Date -Format "yyyy.MM.dd.HHmm"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
# Set error action preference to stop on any error
|
||||||
|
$ErrorActionPreference = "Stop"
|
||||||
|
|
||||||
|
# Display build information
|
||||||
|
Write-Host "Building Docker image: $imageName" -ForegroundColor Green
|
||||||
|
Write-Host "Tag: $tag" -ForegroundColor Green
|
||||||
|
if ($registry) {
|
||||||
|
Write-Host "Registry: $registry" -ForegroundColor Green
|
||||||
|
}
|
||||||
|
|
||||||
|
# Determine the full image name
|
||||||
|
$fullImageName = if ($registry) { "$registry/$imageName" } else { $imageName }
|
||||||
|
|
||||||
|
# Check if Docker is available
|
||||||
|
try {
|
||||||
|
docker --version
|
||||||
|
}
|
||||||
|
catch {
|
||||||
|
Write-Host "Docker is not available. Please install Docker and try again." -ForegroundColor Red
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
|
||||||
|
# Build the Docker image
|
||||||
|
try {
|
||||||
|
Write-Host "Building image: $fullImageName`:$tag" -ForegroundColor Cyan
|
||||||
|
|
||||||
|
# Navigate to the root directory (two levels up from the script location)
|
||||||
|
$rootDir = (Get-Item $PSScriptRoot).Parent.Parent.FullName
|
||||||
|
|
||||||
|
# Build the Docker image
|
||||||
|
docker build -t "$fullImageName`:$tag" -f "$PSScriptRoot/Dockerfile" $rootDir
|
||||||
|
|
||||||
|
if ($LASTEXITCODE -ne 0) {
|
||||||
|
throw "Docker build failed with exit code $LASTEXITCODE"
|
||||||
|
}
|
||||||
|
|
||||||
|
Write-Host "Successfully built image: $fullImageName`:$tag" -ForegroundColor Green
|
||||||
|
|
||||||
|
# Push the image if requested
|
||||||
|
if ($push) {
|
||||||
|
Write-Host "Pushing image to registry: $fullImageName`:$tag" -ForegroundColor Cyan
|
||||||
|
docker push "$fullImageName`:$tag"
|
||||||
|
|
||||||
|
if ($LASTEXITCODE -ne 0) {
|
||||||
|
throw "Docker push failed with exit code $LASTEXITCODE"
|
||||||
|
}
|
||||||
|
|
||||||
|
Write-Host "Successfully pushed image: $fullImageName`:$tag" -ForegroundColor Green
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch {
|
||||||
|
Write-Host "Error: $_" -ForegroundColor Red
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
@@ -0,0 +1,91 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
# Bash script for building Docker images (Linux/macOS)
|
||||||
|
|
||||||
|
# Default values
|
||||||
|
TAG=""
|
||||||
|
REGISTRY=""
|
||||||
|
PUSH=false
|
||||||
|
IMAGE_NAME="ActiveDirectoryManager"
|
||||||
|
|
||||||
|
# If no tag is provided, use the version from version.txt
|
||||||
|
if [ -z "$TAG" ]; then
|
||||||
|
VERSION_FILE="$(dirname "$(dirname "$0")")/version.txt"
|
||||||
|
if [ -f "$VERSION_FILE" ]; then
|
||||||
|
TAG=$(cat "$VERSION_FILE" | tr -d '[:space:]')
|
||||||
|
else
|
||||||
|
# If version.txt doesn't exist, use current date/time in yyyy.MM.dd.HHmm format
|
||||||
|
TAG=$(date +"%Y.%m.%d.%H%M")
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Parse command line arguments
|
||||||
|
while [[ $# -gt 0 ]]; do
|
||||||
|
case $1 in
|
||||||
|
--tag)
|
||||||
|
TAG="$2"
|
||||||
|
shift 2
|
||||||
|
;;
|
||||||
|
--registry)
|
||||||
|
REGISTRY="$2"
|
||||||
|
shift 2
|
||||||
|
;;
|
||||||
|
--push)
|
||||||
|
PUSH=true
|
||||||
|
shift
|
||||||
|
;;
|
||||||
|
--image-name)
|
||||||
|
IMAGE_NAME="$2"
|
||||||
|
shift 2
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
echo "Unknown option: $1"
|
||||||
|
exit 1
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
done
|
||||||
|
|
||||||
|
# Determine the full image name
|
||||||
|
if [ -n "$REGISTRY" ]; then
|
||||||
|
FULL_IMAGE_NAME="$REGISTRY/$IMAGE_NAME"
|
||||||
|
else
|
||||||
|
FULL_IMAGE_NAME="$IMAGE_NAME"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Display build information
|
||||||
|
echo -e "\e[32mBuilding Docker image: $IMAGE_NAME\e[0m"
|
||||||
|
echo -e "\e[32mTag: $TAG\e[0m"
|
||||||
|
if [ -n "$REGISTRY" ]; then
|
||||||
|
echo -e "\e[32mRegistry: $REGISTRY\e[0m"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Check if Docker is available
|
||||||
|
if ! command -v docker &> /dev/null; then
|
||||||
|
echo -e "\e[31mDocker is not available. Please install Docker and try again.\e[0m"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Build the Docker image
|
||||||
|
echo -e "\e[36mBuilding image: $FULL_IMAGE_NAME:$TAG\e[0m"
|
||||||
|
|
||||||
|
# Navigate to the root directory (two levels up from the script location)
|
||||||
|
ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)"
|
||||||
|
|
||||||
|
# Build the Docker image
|
||||||
|
if ! docker build -t "$FULL_IMAGE_NAME:$TAG" -f "$(dirname "${BASH_SOURCE[0]}")/Dockerfile" "$ROOT_DIR"; then
|
||||||
|
echo -e "\e[31mDocker build failed\e[0m"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo -e "\e[32mSuccessfully built image: $FULL_IMAGE_NAME:$TAG\e[0m"
|
||||||
|
|
||||||
|
# Push the image if requested
|
||||||
|
if [ "$PUSH" = true ]; then
|
||||||
|
echo -e "\e[36mPushing image to registry: $FULL_IMAGE_NAME:$TAG\e[0m"
|
||||||
|
|
||||||
|
if ! docker push "$FULL_IMAGE_NAME:$TAG"; then
|
||||||
|
echo -e "\e[31mDocker push failed\e[0m"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo -e "\e[32mSuccessfully pushed image: $FULL_IMAGE_NAME:$TAG\e[0m"
|
||||||
|
fi
|
||||||
@@ -1,9 +1,10 @@
|
|||||||
services:
|
services:
|
||||||
app:
|
app:
|
||||||
build:
|
build:
|
||||||
context: .
|
context: ../../
|
||||||
dockerfile: Dockerfile
|
dockerfile: iac/docker/Dockerfile
|
||||||
container_name: ad-management-api
|
image: ActiveDirectoryManager:${VERSION:-latest}
|
||||||
|
container_name: ActiveDirectoryManager-api
|
||||||
restart: unless-stopped
|
restart: unless-stopped
|
||||||
ports:
|
ports:
|
||||||
- "5000:5000"
|
- "5000:5000"
|
||||||
@@ -34,7 +35,7 @@ services:
|
|||||||
|
|
||||||
postgres:
|
postgres:
|
||||||
image: postgres:15-alpine
|
image: postgres:15-alpine
|
||||||
container_name: ad-management-postgres
|
container_name: ActiveDirectoryManager-postgres
|
||||||
restart: unless-stopped
|
restart: unless-stopped
|
||||||
environment:
|
environment:
|
||||||
- POSTGRES_PASSWORD=${POSTGRES_PASSWORD}
|
- POSTGRES_PASSWORD=${POSTGRES_PASSWORD}
|
||||||
@@ -55,7 +56,7 @@ services:
|
|||||||
|
|
||||||
redis:
|
redis:
|
||||||
image: redis:7-alpine
|
image: redis:7-alpine
|
||||||
container_name: ad-management-redis
|
container_name: ActiveDirectoryManager-redis
|
||||||
restart: unless-stopped
|
restart: unless-stopped
|
||||||
command: redis-server --appendonly yes
|
command: redis-server --appendonly yes
|
||||||
volumes:
|
volumes:
|
||||||
@@ -76,4 +77,4 @@ networks:
|
|||||||
|
|
||||||
volumes:
|
volumes:
|
||||||
postgres-data:
|
postgres-data:
|
||||||
redis-data:
|
redis-data:
|
||||||
@@ -0,0 +1,14 @@
|
|||||||
|
apiVersion: v1
|
||||||
|
kind: ConfigMap
|
||||||
|
metadata:
|
||||||
|
name: ad-management-config
|
||||||
|
namespace: ad-management
|
||||||
|
data:
|
||||||
|
NODE_ENV: "production"
|
||||||
|
PORT: "5000"
|
||||||
|
BASE_URL: "https://ad-management.example.com"
|
||||||
|
DEFAULT_ADMIN_USERNAME: "admin"
|
||||||
|
DEFAULT_ADMIN_FULLNAME: "System Administrator"
|
||||||
|
DISABLE_REGISTRATION: "false"
|
||||||
|
POSTGRES_DB: "admgr"
|
||||||
|
POSTGRES_USER: "postgres"
|
||||||
@@ -0,0 +1,73 @@
|
|||||||
|
apiVersion: apps/v1
|
||||||
|
kind: Deployment
|
||||||
|
metadata:
|
||||||
|
name: ad-management
|
||||||
|
namespace: ad-management
|
||||||
|
spec:
|
||||||
|
replicas: 2
|
||||||
|
selector:
|
||||||
|
matchLabels:
|
||||||
|
app: ad-management
|
||||||
|
template:
|
||||||
|
metadata:
|
||||||
|
labels:
|
||||||
|
app: ad-management
|
||||||
|
spec:
|
||||||
|
containers:
|
||||||
|
- name: activedirectorymanager
|
||||||
|
image: ActiveDirectoryManager:2025.05.21.1430
|
||||||
|
imagePullPolicy: Always
|
||||||
|
ports:
|
||||||
|
- containerPort: 5000
|
||||||
|
name: http
|
||||||
|
envFrom:
|
||||||
|
- configMapRef:
|
||||||
|
name: ad-management-config
|
||||||
|
- secretRef:
|
||||||
|
name: ad-management-secrets
|
||||||
|
env:
|
||||||
|
- name: REDIS_HOST
|
||||||
|
value: "redis"
|
||||||
|
- name: REDIS_PORT
|
||||||
|
value: "6379"
|
||||||
|
- name: POSTGRES_HOST
|
||||||
|
value: "postgres"
|
||||||
|
- name: POSTGRES_PORT
|
||||||
|
value: "5432"
|
||||||
|
resources:
|
||||||
|
requests:
|
||||||
|
memory: "256Mi"
|
||||||
|
cpu: "100m"
|
||||||
|
limits:
|
||||||
|
memory: "512Mi"
|
||||||
|
cpu: "300m"
|
||||||
|
livenessProbe:
|
||||||
|
httpGet:
|
||||||
|
path: /api/health
|
||||||
|
port: http
|
||||||
|
initialDelaySeconds: 30
|
||||||
|
periodSeconds: 10
|
||||||
|
timeoutSeconds: 5
|
||||||
|
failureThreshold: 3
|
||||||
|
readinessProbe:
|
||||||
|
httpGet:
|
||||||
|
path: /api/health
|
||||||
|
port: http
|
||||||
|
initialDelaySeconds: 5
|
||||||
|
periodSeconds: 5
|
||||||
|
timeoutSeconds: 3
|
||||||
|
failureThreshold: 1
|
||||||
|
---
|
||||||
|
apiVersion: v1
|
||||||
|
kind: Service
|
||||||
|
metadata:
|
||||||
|
name: ad-management
|
||||||
|
namespace: ad-management
|
||||||
|
spec:
|
||||||
|
selector:
|
||||||
|
app: ad-management
|
||||||
|
ports:
|
||||||
|
- port: 80
|
||||||
|
targetPort: 5000
|
||||||
|
name: http
|
||||||
|
type: ClusterIP
|
||||||
@@ -0,0 +1,26 @@
|
|||||||
|
apiVersion: networking.k8s.io/v1
|
||||||
|
kind: Ingress
|
||||||
|
metadata:
|
||||||
|
name: ad-management-ingress
|
||||||
|
namespace: ad-management
|
||||||
|
annotations:
|
||||||
|
kubernetes.io/ingress.class: "nginx"
|
||||||
|
cert-manager.io/cluster-issuer: "letsencrypt-prod"
|
||||||
|
nginx.ingress.kubernetes.io/ssl-redirect: "true"
|
||||||
|
nginx.ingress.kubernetes.io/proxy-body-size: "50m"
|
||||||
|
spec:
|
||||||
|
tls:
|
||||||
|
- hosts:
|
||||||
|
- ad-management.example.com
|
||||||
|
secretName: ad-management-tls
|
||||||
|
rules:
|
||||||
|
- host: ad-management.example.com
|
||||||
|
http:
|
||||||
|
paths:
|
||||||
|
- path: /
|
||||||
|
pathType: Prefix
|
||||||
|
backend:
|
||||||
|
service:
|
||||||
|
name: ad-management
|
||||||
|
port:
|
||||||
|
name: http
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
apiVersion: kustomize.config.k8s.io/v1beta1
|
||||||
|
kind: Kustomization
|
||||||
|
|
||||||
|
namespace: ad-management
|
||||||
|
|
||||||
|
resources:
|
||||||
|
- namespace.yaml
|
||||||
|
- configmap.yaml
|
||||||
|
- secrets.yaml
|
||||||
|
- postgres.yaml
|
||||||
|
- redis.yaml
|
||||||
|
- deployment.yaml
|
||||||
|
- ingress.yaml
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
apiVersion: v1
|
||||||
|
kind: Namespace
|
||||||
|
metadata:
|
||||||
|
name: ad-management
|
||||||
|
labels:
|
||||||
|
name: ad-management
|
||||||
@@ -0,0 +1,89 @@
|
|||||||
|
apiVersion: apps/v1
|
||||||
|
kind: StatefulSet
|
||||||
|
metadata:
|
||||||
|
name: postgres
|
||||||
|
namespace: ad-management
|
||||||
|
spec:
|
||||||
|
serviceName: postgres
|
||||||
|
replicas: 1
|
||||||
|
selector:
|
||||||
|
matchLabels:
|
||||||
|
app: postgres
|
||||||
|
template:
|
||||||
|
metadata:
|
||||||
|
labels:
|
||||||
|
app: postgres
|
||||||
|
spec:
|
||||||
|
containers:
|
||||||
|
- name: postgres
|
||||||
|
image: postgres:15-alpine
|
||||||
|
ports:
|
||||||
|
- containerPort: 5432
|
||||||
|
name: postgres
|
||||||
|
env:
|
||||||
|
- name: POSTGRES_DB
|
||||||
|
valueFrom:
|
||||||
|
configMapKeyRef:
|
||||||
|
name: ad-management-config
|
||||||
|
key: POSTGRES_DB
|
||||||
|
- name: POSTGRES_USER
|
||||||
|
valueFrom:
|
||||||
|
configMapKeyRef:
|
||||||
|
name: ad-management-config
|
||||||
|
key: POSTGRES_USER
|
||||||
|
- name: POSTGRES_PASSWORD
|
||||||
|
valueFrom:
|
||||||
|
secretKeyRef:
|
||||||
|
name: ad-management-secrets
|
||||||
|
key: POSTGRES_PASSWORD
|
||||||
|
volumeMounts:
|
||||||
|
- name: postgres-data
|
||||||
|
mountPath: /var/lib/postgresql/data
|
||||||
|
resources:
|
||||||
|
requests:
|
||||||
|
memory: "256Mi"
|
||||||
|
cpu: "100m"
|
||||||
|
limits:
|
||||||
|
memory: "1Gi"
|
||||||
|
cpu: "500m"
|
||||||
|
livenessProbe:
|
||||||
|
exec:
|
||||||
|
command:
|
||||||
|
- pg_isready
|
||||||
|
- -U
|
||||||
|
- postgres
|
||||||
|
initialDelaySeconds: 30
|
||||||
|
periodSeconds: 10
|
||||||
|
timeoutSeconds: 5
|
||||||
|
failureThreshold: 3
|
||||||
|
readinessProbe:
|
||||||
|
exec:
|
||||||
|
command:
|
||||||
|
- pg_isready
|
||||||
|
- -U
|
||||||
|
- postgres
|
||||||
|
initialDelaySeconds: 5
|
||||||
|
periodSeconds: 5
|
||||||
|
timeoutSeconds: 3
|
||||||
|
failureThreshold: 1
|
||||||
|
volumeClaimTemplates:
|
||||||
|
- metadata:
|
||||||
|
name: postgres-data
|
||||||
|
spec:
|
||||||
|
accessModes: [ "ReadWriteOnce" ]
|
||||||
|
resources:
|
||||||
|
requests:
|
||||||
|
storage: 10Gi
|
||||||
|
---
|
||||||
|
apiVersion: v1
|
||||||
|
kind: Service
|
||||||
|
metadata:
|
||||||
|
name: postgres
|
||||||
|
namespace: ad-management
|
||||||
|
spec:
|
||||||
|
selector:
|
||||||
|
app: postgres
|
||||||
|
ports:
|
||||||
|
- port: 5432
|
||||||
|
targetPort: 5432
|
||||||
|
clusterIP: None # Headless service for StatefulSet
|
||||||
@@ -0,0 +1,71 @@
|
|||||||
|
apiVersion: apps/v1
|
||||||
|
kind: StatefulSet
|
||||||
|
metadata:
|
||||||
|
name: redis
|
||||||
|
namespace: ad-management
|
||||||
|
spec:
|
||||||
|
serviceName: redis
|
||||||
|
replicas: 1
|
||||||
|
selector:
|
||||||
|
matchLabels:
|
||||||
|
app: redis
|
||||||
|
template:
|
||||||
|
metadata:
|
||||||
|
labels:
|
||||||
|
app: redis
|
||||||
|
spec:
|
||||||
|
containers:
|
||||||
|
- name: redis
|
||||||
|
image: redis:7-alpine
|
||||||
|
ports:
|
||||||
|
- containerPort: 6379
|
||||||
|
name: redis
|
||||||
|
volumeMounts:
|
||||||
|
- name: redis-data
|
||||||
|
mountPath: /data
|
||||||
|
resources:
|
||||||
|
requests:
|
||||||
|
memory: "128Mi"
|
||||||
|
cpu: "50m"
|
||||||
|
limits:
|
||||||
|
memory: "256Mi"
|
||||||
|
cpu: "200m"
|
||||||
|
livenessProbe:
|
||||||
|
exec:
|
||||||
|
command:
|
||||||
|
- redis-cli
|
||||||
|
- ping
|
||||||
|
initialDelaySeconds: 30
|
||||||
|
periodSeconds: 10
|
||||||
|
timeoutSeconds: 5
|
||||||
|
failureThreshold: 3
|
||||||
|
readinessProbe:
|
||||||
|
exec:
|
||||||
|
command:
|
||||||
|
- redis-cli
|
||||||
|
- ping
|
||||||
|
initialDelaySeconds: 5
|
||||||
|
periodSeconds: 5
|
||||||
|
timeoutSeconds: 3
|
||||||
|
failureThreshold: 1
|
||||||
|
volumeClaimTemplates:
|
||||||
|
- metadata:
|
||||||
|
name: redis-data
|
||||||
|
spec:
|
||||||
|
accessModes: [ "ReadWriteOnce" ]
|
||||||
|
resources:
|
||||||
|
requests:
|
||||||
|
storage: 1Gi
|
||||||
|
---
|
||||||
|
apiVersion: v1
|
||||||
|
kind: Service
|
||||||
|
metadata:
|
||||||
|
name: redis
|
||||||
|
namespace: ad-management
|
||||||
|
spec:
|
||||||
|
selector:
|
||||||
|
app: redis
|
||||||
|
ports:
|
||||||
|
- port: 6379
|
||||||
|
targetPort: 6379
|
||||||
|
clusterIP: None # Headless service for StatefulSet
|
||||||
@@ -0,0 +1,14 @@
|
|||||||
|
apiVersion: v1
|
||||||
|
kind: Secret
|
||||||
|
metadata:
|
||||||
|
name: ad-management-secrets
|
||||||
|
namespace: ad-management
|
||||||
|
type: Opaque
|
||||||
|
data:
|
||||||
|
# These are example values. In production, replace with your own base64-encoded secrets
|
||||||
|
# Example: echo -n "your-secret-value" | base64
|
||||||
|
JWT_SECRET: Y2hhbmdlLXRoaXMtaW4tcHJvZHVjdGlvbg==
|
||||||
|
SESSION_SECRET: Y2hhbmdlLXRoaXMtaW4tcHJvZHVjdGlvbg==
|
||||||
|
DEFAULT_ADMIN_PASSWORD: cGFzc3dvcmQ=
|
||||||
|
DEFAULT_ADMIN_EMAIL: YWRtaW5AZXhhbXBsZS5jb20=
|
||||||
|
POSTGRES_PASSWORD: cG9zdGdyZXM=
|
||||||
@@ -0,0 +1,40 @@
|
|||||||
|
# PowerShell script to update the Kubernetes deployment with the current version
|
||||||
|
|
||||||
|
# Get the directory of this script
|
||||||
|
$scriptDir = Split-Path -Parent $MyInvocation.MyCommand.Path
|
||||||
|
$parentDir = Split-Path -Parent $scriptDir
|
||||||
|
|
||||||
|
# Read the version from version.txt
|
||||||
|
$versionFile = Join-Path $parentDir "version.txt"
|
||||||
|
if (-not (Test-Path $versionFile)) {
|
||||||
|
Write-Host "Error: version.txt not found at $versionFile" -ForegroundColor Red
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
|
||||||
|
$version = Get-Content $versionFile -Raw
|
||||||
|
$version = $version.Trim()
|
||||||
|
Write-Host "Using version: $version" -ForegroundColor Cyan
|
||||||
|
|
||||||
|
# Update the deployment.yaml file
|
||||||
|
$deploymentFile = Join-Path $scriptDir "deployment.yaml"
|
||||||
|
if (-not (Test-Path $deploymentFile)) {
|
||||||
|
Write-Host "Error: deployment.yaml not found at $deploymentFile" -ForegroundColor Red
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
|
||||||
|
# Read the deployment file
|
||||||
|
$content = Get-Content $deploymentFile -Raw
|
||||||
|
|
||||||
|
# Replace the image version
|
||||||
|
$pattern1 = 'image: ActiveDirectoryManager:[0-9]{4}\.[0-9]{2}\.[0-9]{2}\.[0-9]{4}'
|
||||||
|
$replacement1 = "image: ActiveDirectoryManager:$version"
|
||||||
|
$content = $content -replace $pattern1, $replacement1
|
||||||
|
|
||||||
|
$pattern2 = 'image: ActiveDirectoryManager:latest'
|
||||||
|
$replacement2 = "image: ActiveDirectoryManager:$version"
|
||||||
|
$content = $content -replace $pattern2, $replacement2
|
||||||
|
|
||||||
|
# Write the updated content back to the file
|
||||||
|
$content | Set-Content $deploymentFile
|
||||||
|
|
||||||
|
Write-Host "Updated deployment.yaml with version $version" -ForegroundColor Green
|
||||||
@@ -0,0 +1,36 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
# Script to update the Kubernetes deployment with the current version
|
||||||
|
|
||||||
|
# Get the directory of this script
|
||||||
|
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||||
|
PARENT_DIR="$(dirname "$SCRIPT_DIR")"
|
||||||
|
|
||||||
|
# Read the version from version.txt
|
||||||
|
VERSION_FILE="$PARENT_DIR/version.txt"
|
||||||
|
if [ ! -f "$VERSION_FILE" ]; then
|
||||||
|
echo "Error: version.txt not found at $VERSION_FILE"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
VERSION=$(cat "$VERSION_FILE" | tr -d '[:space:]')
|
||||||
|
echo "Using version: $VERSION"
|
||||||
|
|
||||||
|
# Update the deployment.yaml file
|
||||||
|
DEPLOYMENT_FILE="$SCRIPT_DIR/deployment.yaml"
|
||||||
|
if [ ! -f "$DEPLOYMENT_FILE" ]; then
|
||||||
|
echo "Error: deployment.yaml not found at $DEPLOYMENT_FILE"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Use sed to replace the image version
|
||||||
|
if [[ "$OSTYPE" == "darwin"* ]]; then
|
||||||
|
# macOS requires a different sed syntax
|
||||||
|
sed -i '' "s|image: ActiveDirectoryManager:[0-9]\{4\}\.[0-9]\{2\}\.[0-9]\{2\}\.[0-9]\{4\}|image: ActiveDirectoryManager:$VERSION|g" "$DEPLOYMENT_FILE"
|
||||||
|
sed -i '' "s|image: ActiveDirectoryManager:latest|image: ActiveDirectoryManager:$VERSION|g" "$DEPLOYMENT_FILE"
|
||||||
|
else
|
||||||
|
# Linux
|
||||||
|
sed -i "s|image: ActiveDirectoryManager:[0-9]\{4\}\.[0-9]\{2\}\.[0-9]\{2\}\.[0-9]\{4\}|image: ActiveDirectoryManager:$VERSION|g" "$DEPLOYMENT_FILE"
|
||||||
|
sed -i "s|image: ActiveDirectoryManager:latest|image: ActiveDirectoryManager:$VERSION|g" "$DEPLOYMENT_FILE"
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "Updated deployment.yaml with version $VERSION"
|
||||||
@@ -0,0 +1,24 @@
|
|||||||
|
# PowerShell script to update version and apply it to all components
|
||||||
|
|
||||||
|
# Get the directory of this script
|
||||||
|
$scriptDir = Split-Path -Parent $MyInvocation.MyCommand.Path
|
||||||
|
|
||||||
|
# Update version.txt with current date/time
|
||||||
|
Write-Host "Updating version.txt..." -ForegroundColor Cyan
|
||||||
|
& "$scriptDir\update-version.ps1"
|
||||||
|
|
||||||
|
# Read the new version
|
||||||
|
$version = Get-Content "$scriptDir\version.txt" -Raw
|
||||||
|
$version = $version.Trim()
|
||||||
|
Write-Host "New version: $version" -ForegroundColor Green
|
||||||
|
|
||||||
|
# Update Kubernetes deployment
|
||||||
|
Write-Host "Updating Kubernetes deployment..." -ForegroundColor Cyan
|
||||||
|
& "$scriptDir\kubernetes\update-deployment-version.ps1"
|
||||||
|
|
||||||
|
Write-Host "Version update complete. New version: $version" -ForegroundColor Green
|
||||||
|
Write-Host ""
|
||||||
|
Write-Host "Next steps:" -ForegroundColor Yellow
|
||||||
|
Write-Host "1. Build Docker image: cd $scriptDir\docker; .\build.ps1" -ForegroundColor Yellow
|
||||||
|
Write-Host "2. Push Docker image: cd $scriptDir\docker; .\build.ps1 -push" -ForegroundColor Yellow
|
||||||
|
Write-Host "3. Deploy to Kubernetes: cd $scriptDir\kubernetes; kubectl apply -k ." -ForegroundColor Yellow
|
||||||
@@ -0,0 +1,24 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
# Comprehensive script to update version and apply it to all components
|
||||||
|
|
||||||
|
# Get the directory of this script
|
||||||
|
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||||
|
|
||||||
|
# Update version.txt with current date/time
|
||||||
|
echo "Updating version.txt..."
|
||||||
|
"$SCRIPT_DIR/update-version.sh"
|
||||||
|
|
||||||
|
# Read the new version
|
||||||
|
VERSION=$(cat "$SCRIPT_DIR/version.txt" | tr -d '[:space:]')
|
||||||
|
echo "New version: $VERSION"
|
||||||
|
|
||||||
|
# Update Kubernetes deployment
|
||||||
|
echo "Updating Kubernetes deployment..."
|
||||||
|
"$SCRIPT_DIR/kubernetes/update-deployment-version.sh"
|
||||||
|
|
||||||
|
echo "Version update complete. New version: $VERSION"
|
||||||
|
echo ""
|
||||||
|
echo "Next steps:"
|
||||||
|
echo "1. Build Docker image: cd $SCRIPT_DIR/docker && ./build.sh"
|
||||||
|
echo "2. Push Docker image: cd $SCRIPT_DIR/docker && ./build.sh --push"
|
||||||
|
echo "3. Deploy to Kubernetes: cd $SCRIPT_DIR/kubernetes && kubectl apply -k ."
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
# PowerShell script to update the version.txt file with the current date and time
|
||||||
|
|
||||||
|
# Generate version in yyyy.MM.dd.HHmm format
|
||||||
|
$version = Get-Date -Format "yyyy.MM.dd.HHmm"
|
||||||
|
|
||||||
|
# Update version.txt
|
||||||
|
$versionFile = Join-Path $PSScriptRoot "version.txt"
|
||||||
|
$version | Out-File -FilePath $versionFile -NoNewline
|
||||||
|
|
||||||
|
Write-Host "Version updated to: $version"
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
# Script to update the version.txt file with the current date and time
|
||||||
|
|
||||||
|
# Generate version in yyyy.MM.dd.HHmm format
|
||||||
|
VERSION=$(date +"%Y.%m.%d.%H%M")
|
||||||
|
|
||||||
|
# Update version.txt
|
||||||
|
echo "$VERSION" > "$(dirname "$0")/version.txt"
|
||||||
|
|
||||||
|
echo "Version updated to: $VERSION"
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
2025.05.21.1430
|
||||||
+1177
-206
File diff suppressed because it is too large
Load Diff
+1630
-536
File diff suppressed because it is too large
Load Diff
+95
-16
@@ -35,6 +35,32 @@ const swaggerOptions = {
|
|||||||
description: "API base URL",
|
description: "API base URL",
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
|
tags: [
|
||||||
|
{
|
||||||
|
name: "LDAP Connections",
|
||||||
|
description: "Operations for managing LDAP connections"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "AD Users",
|
||||||
|
description: "Operations for managing Active Directory users"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "AD Groups",
|
||||||
|
description: "Operations for managing Active Directory groups"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "AD Computers",
|
||||||
|
description: "Operations for managing Active Directory computers"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "AD Organizational Units",
|
||||||
|
description: "Operations for managing Active Directory organizational units"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Active Directory",
|
||||||
|
description: "General Active Directory operations including password management and account status"
|
||||||
|
}
|
||||||
|
],
|
||||||
components: {
|
components: {
|
||||||
securitySchemes: {
|
securitySchemes: {
|
||||||
bearerAuth: {
|
bearerAuth: {
|
||||||
@@ -299,7 +325,7 @@ const swaggerOptions = {
|
|||||||
id: { type: "integer" },
|
id: { type: "integer" },
|
||||||
action: { type: "string" },
|
action: { type: "string" },
|
||||||
targetId: { type: "string" },
|
targetId: { type: "string" },
|
||||||
details: {
|
details: {
|
||||||
type: "object",
|
type: "object",
|
||||||
additionalProperties: true
|
additionalProperties: true
|
||||||
},
|
},
|
||||||
@@ -308,6 +334,59 @@ const swaggerOptions = {
|
|||||||
connectionId: { type: "integer" }
|
connectionId: { type: "integer" }
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
PasswordReset: {
|
||||||
|
type: "object",
|
||||||
|
required: ["userObjectGUID", "newPassword"],
|
||||||
|
properties: {
|
||||||
|
userObjectGUID: {
|
||||||
|
type: "string",
|
||||||
|
description: "The ObjectGUID of the user"
|
||||||
|
},
|
||||||
|
newPassword: {
|
||||||
|
type: "string",
|
||||||
|
description: "The new password for the user"
|
||||||
|
},
|
||||||
|
skipValidation: {
|
||||||
|
type: "boolean",
|
||||||
|
description: "Whether to skip password policy validation",
|
||||||
|
default: false
|
||||||
|
},
|
||||||
|
requirePasswordChangeAtNextLogon: {
|
||||||
|
type: "boolean",
|
||||||
|
description: "Whether to require the user to change their password at next logon",
|
||||||
|
default: true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
EnableUserAccount: {
|
||||||
|
type: "object",
|
||||||
|
required: ["userObjectGUID", "enabled"],
|
||||||
|
properties: {
|
||||||
|
userObjectGUID: {
|
||||||
|
type: "string",
|
||||||
|
description: "The ObjectGUID of the user"
|
||||||
|
},
|
||||||
|
enabled: {
|
||||||
|
type: "boolean",
|
||||||
|
description: "Whether to enable or disable the account"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
BulkEnableUserAccounts: {
|
||||||
|
type: "object",
|
||||||
|
required: ["userDNs", "enabled"],
|
||||||
|
properties: {
|
||||||
|
userDNs: {
|
||||||
|
type: "array",
|
||||||
|
items: { type: "string" },
|
||||||
|
description: "Array of user distinguished names"
|
||||||
|
},
|
||||||
|
enabled: {
|
||||||
|
type: "boolean",
|
||||||
|
description: "Whether to enable or disable the accounts"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
},
|
},
|
||||||
responses: {
|
responses: {
|
||||||
UnauthorizedError: {
|
UnauthorizedError: {
|
||||||
@@ -394,13 +473,13 @@ export function setupSwagger(app: Express) {
|
|||||||
// Mount at both paths for backward compatibility
|
// Mount at both paths for backward compatibility
|
||||||
app.use("/api/docs", swaggerUi.serve, swaggerUi.setup(swaggerSpec, swaggerUiOptions));
|
app.use("/api/docs", swaggerUi.serve, swaggerUi.setup(swaggerSpec, swaggerUiOptions));
|
||||||
app.use("/api-docs", swaggerUi.serve, swaggerUi.setup(swaggerSpec, swaggerUiOptions));
|
app.use("/api-docs", swaggerUi.serve, swaggerUi.setup(swaggerSpec, swaggerUiOptions));
|
||||||
|
|
||||||
// Provide the JSON spec at multiple paths
|
// Provide the JSON spec at multiple paths
|
||||||
app.get("/api/swagger.json", (req, res) => {
|
app.get("/api/swagger.json", (req, res) => {
|
||||||
res.setHeader("Content-Type", "application/json");
|
res.setHeader("Content-Type", "application/json");
|
||||||
res.send(swaggerSpec);
|
res.send(swaggerSpec);
|
||||||
});
|
});
|
||||||
|
|
||||||
app.get("/api-docs/swagger.json", (req, res) => {
|
app.get("/api-docs/swagger.json", (req, res) => {
|
||||||
res.setHeader("Content-Type", "application/json");
|
res.setHeader("Content-Type", "application/json");
|
||||||
res.send(swaggerSpec);
|
res.send(swaggerSpec);
|
||||||
@@ -408,8 +487,8 @@ export function setupSwagger(app: Express) {
|
|||||||
|
|
||||||
// Add download endpoint for the OpenAPI specification
|
// Add download endpoint for the OpenAPI specification
|
||||||
app.get("/api/docs/download", (req, res) => {
|
app.get("/api/docs/download", (req, res) => {
|
||||||
const format = req.query.format?.toString().toLowerCase() || 'json';
|
const format = req.query.format?.toString().toLowerCase() ?? 'json';
|
||||||
|
|
||||||
if (format === 'json') {
|
if (format === 'json') {
|
||||||
res.setHeader('Content-Disposition', 'attachment; filename=openapi-spec.json');
|
res.setHeader('Content-Disposition', 'attachment; filename=openapi-spec.json');
|
||||||
res.setHeader('Content-Type', 'application/json');
|
res.setHeader('Content-Type', 'application/json');
|
||||||
@@ -455,7 +534,7 @@ export function setupSwagger(app: Express) {
|
|||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<h1>Active Directory Management API - Advanced Usage Guide</h1>
|
<h1>Active Directory Management API - Advanced Usage Guide</h1>
|
||||||
|
|
||||||
<h2>API Documentation</h2>
|
<h2>API Documentation</h2>
|
||||||
<p>The complete API documentation is available at <a href="/api/docs">/api/docs</a>.</p>
|
<p>The complete API documentation is available at <a href="/api/docs">/api/docs</a>.</p>
|
||||||
<p>You can also download the OpenAPI specification:</p>
|
<p>You can also download the OpenAPI specification:</p>
|
||||||
@@ -463,28 +542,28 @@ export function setupSwagger(app: Express) {
|
|||||||
<a href="/api/docs/download?format=json" class="btn">Download OpenAPI Spec (JSON)</a>
|
<a href="/api/docs/download?format=json" class="btn">Download OpenAPI Spec (JSON)</a>
|
||||||
<a href="/api/docs/download?format=yaml" class="btn">Download OpenAPI Spec (YAML)</a>
|
<a href="/api/docs/download?format=yaml" class="btn">Download OpenAPI Spec (YAML)</a>
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<h2>Query Parameters and Filtering</h2>
|
<h2>Query Parameters and Filtering</h2>
|
||||||
<pre>${queryParamsInfo}</pre>
|
<pre>${queryParamsInfo}</pre>
|
||||||
|
|
||||||
<h2>Authentication</h2>
|
<h2>Authentication</h2>
|
||||||
<p>This API supports two authentication methods:</p>
|
<p>This API supports two authentication methods:</p>
|
||||||
<ul>
|
<ul>
|
||||||
<li><strong>Session-based authentication</strong>: Used when accessing the API from the web interface.</li>
|
<li><strong>Session-based authentication</strong>: Used when accessing the API from the web interface.</li>
|
||||||
<li><strong>API Token authentication</strong>: Used when accessing the API programmatically.</li>
|
<li><strong>API Token authentication</strong>: Used when accessing the API programmatically.</li>
|
||||||
</ul>
|
</ul>
|
||||||
|
|
||||||
<h3>API Token Authentication</h3>
|
<h3>API Token Authentication</h3>
|
||||||
<p>To authenticate using an API token, include the token in the Authorization header:</p>
|
<p>To authenticate using an API token, include the token in the Authorization header:</p>
|
||||||
<pre>Authorization: Bearer YOUR_API_TOKEN</pre>
|
<pre>Authorization: Bearer YOUR_API_TOKEN</pre>
|
||||||
|
|
||||||
<h2>Rate Limiting</h2>
|
<h2>Rate Limiting</h2>
|
||||||
<p>The API has rate limiting in place to prevent abuse. The current limits are:</p>
|
<p>The API has rate limiting in place to prevent abuse. The current limits are:</p>
|
||||||
<ul>
|
<ul>
|
||||||
<li>100 requests per minute for authenticated users</li>
|
<li>100 requests per minute for authenticated users</li>
|
||||||
<li>20 requests per minute for unauthenticated users</li>
|
<li>20 requests per minute for unauthenticated users</li>
|
||||||
</ul>
|
</ul>
|
||||||
|
|
||||||
<h2>Error Handling</h2>
|
<h2>Error Handling</h2>
|
||||||
<p>The API returns consistent error responses with the following structure:</p>
|
<p>The API returns consistent error responses with the following structure:</p>
|
||||||
<pre>{
|
<pre>{
|
||||||
@@ -496,20 +575,20 @@ export function setupSwagger(app: Express) {
|
|||||||
}
|
}
|
||||||
]
|
]
|
||||||
}</pre>
|
}</pre>
|
||||||
|
|
||||||
<h2>Example Usage</h2>
|
<h2>Example Usage</h2>
|
||||||
<h3>Filter Users by Name</h3>
|
<h3>Filter Users by Name</h3>
|
||||||
<pre>GET /api/connections/1/ad-users?filter=displayName contains 'John'</pre>
|
<pre>GET /api/connections/1/ad-users?filter=displayName contains 'John'</pre>
|
||||||
|
|
||||||
<h3>Select Specific Fields</h3>
|
<h3>Select Specific Fields</h3>
|
||||||
<pre>GET /api/connections/1/ad-users?select=id,displayName,email</pre>
|
<pre>GET /api/connections/1/ad-users?select=id,displayName,email</pre>
|
||||||
|
|
||||||
<h3>Pagination</h3>
|
<h3>Pagination</h3>
|
||||||
<pre>GET /api/connections/1/ad-users?top=10&skip=20</pre>
|
<pre>GET /api/connections/1/ad-users?top=10&skip=20</pre>
|
||||||
|
|
||||||
<h3>Combining Parameters</h3>
|
<h3>Combining Parameters</h3>
|
||||||
<pre>GET /api/connections/1/ad-users?filter=enabled eq true&select=id,displayName,email&orderBy=displayName asc&top=10</pre>
|
<pre>GET /api/connections/1/ad-users?filter=enabled eq true&select=id,displayName,email&orderBy=displayName asc&top=10</pre>
|
||||||
|
|
||||||
<p>Return to <a href="/api/docs">API Documentation</a></p>
|
<p>Return to <a href="/api/docs">API Documentation</a></p>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|||||||
+77
-27
@@ -19,48 +19,48 @@ export const PERMISSIONS = {
|
|||||||
CREATE_USERS: "create:users",
|
CREATE_USERS: "create:users",
|
||||||
UPDATE_USERS: "update:users",
|
UPDATE_USERS: "update:users",
|
||||||
DELETE_USERS: "delete:users",
|
DELETE_USERS: "delete:users",
|
||||||
|
|
||||||
// LDAP connections
|
// LDAP connections
|
||||||
VIEW_LDAP_CONNECTIONS: "view:ldap_connections",
|
VIEW_LDAP_CONNECTIONS: "view:ldap_connections",
|
||||||
CREATE_LDAP_CONNECTIONS: "create:ldap_connections",
|
CREATE_LDAP_CONNECTIONS: "create:ldap_connections",
|
||||||
UPDATE_LDAP_CONNECTIONS: "update:ldap_connections",
|
UPDATE_LDAP_CONNECTIONS: "update:ldap_connections",
|
||||||
DELETE_LDAP_CONNECTIONS: "delete:ldap_connections",
|
DELETE_LDAP_CONNECTIONS: "delete:ldap_connections",
|
||||||
|
|
||||||
// Active Directory management
|
// Active Directory management
|
||||||
VIEW_AD_USERS: "view:ad_users",
|
VIEW_AD_USERS: "view:ad_users",
|
||||||
CREATE_AD_USERS: "create:ad_users",
|
CREATE_AD_USERS: "create:ad_users",
|
||||||
UPDATE_AD_USERS: "update:ad_users",
|
UPDATE_AD_USERS: "update:ad_users",
|
||||||
DELETE_AD_USERS: "delete:ad_users",
|
DELETE_AD_USERS: "delete:ad_users",
|
||||||
MOVE_AD_USERS: "move:ad_users",
|
MOVE_AD_USERS: "move:ad_users",
|
||||||
|
|
||||||
VIEW_AD_GROUPS: "view:ad_groups",
|
VIEW_AD_GROUPS: "view:ad_groups",
|
||||||
CREATE_AD_GROUPS: "create:ad_groups",
|
CREATE_AD_GROUPS: "create:ad_groups",
|
||||||
UPDATE_AD_GROUPS: "update:ad_groups",
|
UPDATE_AD_GROUPS: "update:ad_groups",
|
||||||
DELETE_AD_GROUPS: "delete:ad_groups",
|
DELETE_AD_GROUPS: "delete:ad_groups",
|
||||||
MANAGE_GROUP_MEMBERSHIP: "manage:group_membership",
|
MANAGE_GROUP_MEMBERSHIP: "manage:group_membership",
|
||||||
|
|
||||||
VIEW_AD_OUS: "view:ad_ous",
|
VIEW_AD_OUS: "view:ad_ous",
|
||||||
CREATE_AD_OUS: "create:ad_ous",
|
CREATE_AD_OUS: "create:ad_ous",
|
||||||
UPDATE_AD_OUS: "update:ad_ous",
|
UPDATE_AD_OUS: "update:ad_ous",
|
||||||
DELETE_AD_OUS: "delete:ad_ous",
|
DELETE_AD_OUS: "delete:ad_ous",
|
||||||
|
|
||||||
VIEW_AD_COMPUTERS: "view:ad_computers",
|
VIEW_AD_COMPUTERS: "view:ad_computers",
|
||||||
CREATE_AD_COMPUTERS: "create:ad_computers",
|
CREATE_AD_COMPUTERS: "create:ad_computers",
|
||||||
UPDATE_AD_COMPUTERS: "update:ad_computers",
|
UPDATE_AD_COMPUTERS: "update:ad_computers",
|
||||||
DELETE_AD_COMPUTERS: "delete:ad_computers",
|
DELETE_AD_COMPUTERS: "delete:ad_computers",
|
||||||
MOVE_AD_COMPUTERS: "move:ad_computers",
|
MOVE_AD_COMPUTERS: "move:ad_computers",
|
||||||
|
|
||||||
VIEW_AD_DOMAINS: "view:ad_domains",
|
VIEW_AD_DOMAINS: "view:ad_domains",
|
||||||
CREATE_AD_DOMAINS: "create:ad_domains",
|
CREATE_AD_DOMAINS: "create:ad_domains",
|
||||||
UPDATE_AD_DOMAINS: "update:ad_domains",
|
UPDATE_AD_DOMAINS: "update:ad_domains",
|
||||||
DELETE_AD_DOMAINS: "delete:ad_domains",
|
DELETE_AD_DOMAINS: "delete:ad_domains",
|
||||||
|
|
||||||
// Sites and Services management
|
// Sites and Services management
|
||||||
VIEW_AD_SITES: "view:ad_sites",
|
VIEW_AD_SITES: "view:ad_sites",
|
||||||
CREATE_AD_SITES: "create:ad_sites",
|
CREATE_AD_SITES: "create:ad_sites",
|
||||||
UPDATE_AD_SITES: "update:ad_sites",
|
UPDATE_AD_SITES: "update:ad_sites",
|
||||||
DELETE_AD_SITES: "delete:ad_sites",
|
DELETE_AD_SITES: "delete:ad_sites",
|
||||||
|
|
||||||
VIEW_AD_SUBNETS: "view:ad_subnets",
|
VIEW_AD_SUBNETS: "view:ad_subnets",
|
||||||
CREATE_AD_SUBNETS: "create:ad_subnets",
|
CREATE_AD_SUBNETS: "create:ad_subnets",
|
||||||
UPDATE_AD_SUBNETS: "update:ad_subnets",
|
UPDATE_AD_SUBNETS: "update:ad_subnets",
|
||||||
@@ -68,7 +68,7 @@ export const PERMISSIONS = {
|
|||||||
|
|
||||||
// API Token management
|
// API Token management
|
||||||
MANAGE_API_TOKENS: "manage:api_tokens",
|
MANAGE_API_TOKENS: "manage:api_tokens",
|
||||||
|
|
||||||
// Administrative functions
|
// Administrative functions
|
||||||
MANAGE_ROLES: "manage:roles",
|
MANAGE_ROLES: "manage:roles",
|
||||||
SYSTEM_ADMIN: "admin:system",
|
SYSTEM_ADMIN: "admin:system",
|
||||||
@@ -175,10 +175,10 @@ export const ldapConnections = pgTable("ldap_connections", {
|
|||||||
export const scheduleFrequencies = [
|
export const scheduleFrequencies = [
|
||||||
"once",
|
"once",
|
||||||
"minutely",
|
"minutely",
|
||||||
"hourly",
|
"hourly",
|
||||||
"daily",
|
"daily",
|
||||||
"weekly",
|
"weekly",
|
||||||
"monthly",
|
"monthly",
|
||||||
"yearly"
|
"yearly"
|
||||||
] as const;
|
] as const;
|
||||||
|
|
||||||
@@ -234,7 +234,7 @@ export const dynamicGroupRules = pgTable("dynamic_group_rules", {
|
|||||||
|
|
||||||
// Rule conditions (filter logic)
|
// Rule conditions (filter logic)
|
||||||
export const dynamicGroupConditions = pgTable("dynamic_group_conditions", {
|
export const dynamicGroupConditions = pgTable("dynamic_group_conditions", {
|
||||||
id: serial("id").primaryKey(),
|
id: serial("id").primaryKey(),
|
||||||
ruleId: integer("rule_id").references(() => dynamicGroupRules.id, { onDelete: "cascade" }).notNull(),
|
ruleId: integer("rule_id").references(() => dynamicGroupRules.id, { onDelete: "cascade" }).notNull(),
|
||||||
parentId: integer("parent_id").references(() => dynamicGroupConditions.id, { onDelete: "cascade" }),
|
parentId: integer("parent_id").references(() => dynamicGroupConditions.id, { onDelete: "cascade" }),
|
||||||
type: text("type").notNull(), // "condition", "group"
|
type: text("type").notNull(), // "condition", "group"
|
||||||
@@ -498,6 +498,53 @@ export const removeFromGroupSchema = z.object({
|
|||||||
objectType: z.enum(["user", "computer"]),
|
objectType: z.enum(["user", "computer"]),
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Password management schemas
|
||||||
|
export const resetPasswordSchema = z.object({
|
||||||
|
userObjectGUID: z.string().min(1, "User ObjectGUID is required"),
|
||||||
|
newPassword: z.string().min(8, "Password must be at least 8 characters long"),
|
||||||
|
skipValidation: z.boolean().optional().default(false),
|
||||||
|
requirePasswordChangeAtNextLogon: z.boolean().optional().default(true),
|
||||||
|
});
|
||||||
|
|
||||||
|
export const enableUserAccountSchema = z.object({
|
||||||
|
userObjectGUID: z.string().min(1, "User ObjectGUID is required"),
|
||||||
|
enabled: z.boolean(),
|
||||||
|
});
|
||||||
|
|
||||||
|
// Bulk operations schemas
|
||||||
|
export const bulkEnableUserAccountsSchema = z.object({
|
||||||
|
userDNs: z.array(z.string().min(1, "User DN is required")),
|
||||||
|
enabled: z.boolean(),
|
||||||
|
});
|
||||||
|
|
||||||
|
// Bulk operations schemas
|
||||||
|
export const bulkMoveObjectsSchema = z.object({
|
||||||
|
objectDNs: z.array(z.string().min(1, "Object DN is required")),
|
||||||
|
targetOU: z.string().min(1, "Target OU is required"),
|
||||||
|
});
|
||||||
|
|
||||||
|
export const bulkAddToGroupSchema = z.object({
|
||||||
|
memberDNs: z.array(z.string().min(1, "Member DN is required")),
|
||||||
|
groupDN: z.string().min(1, "Group DN is required"),
|
||||||
|
});
|
||||||
|
|
||||||
|
export const bulkRemoveFromGroupSchema = z.object({
|
||||||
|
memberDNs: z.array(z.string().min(1, "Member DN is required")),
|
||||||
|
groupDN: z.string().min(1, "Group DN is required"),
|
||||||
|
});
|
||||||
|
|
||||||
|
export const bulkEnableUserAccountsSchema = z.object({
|
||||||
|
userDNs: z.array(z.string().min(1, "User DN is required")),
|
||||||
|
enabled: z.boolean(),
|
||||||
|
});
|
||||||
|
|
||||||
|
export const bulkUpdateAttributeSchema = z.object({
|
||||||
|
objectDNs: z.array(z.string().min(1, "Object DN is required")),
|
||||||
|
attributeName: z.string().min(1, "Attribute name is required"),
|
||||||
|
attributeValue: z.union([z.string(), z.array(z.string()), z.null()]),
|
||||||
|
operation: z.enum(["add", "replace", "delete"]).default("replace"),
|
||||||
|
});
|
||||||
|
|
||||||
// ManagedBy operation schema is no longer needed as it's been replaced by object-specific PATCH endpoints
|
// ManagedBy operation schema is no longer needed as it's been replaced by object-specific PATCH endpoints
|
||||||
|
|
||||||
// Export types
|
// Export types
|
||||||
@@ -536,6 +583,9 @@ export type MoveComputer = z.infer<typeof moveComputerSchema>;
|
|||||||
export type MoveUser = z.infer<typeof moveUserSchema>;
|
export type MoveUser = z.infer<typeof moveUserSchema>;
|
||||||
export type AddToGroup = z.infer<typeof addToGroupSchema>;
|
export type AddToGroup = z.infer<typeof addToGroupSchema>;
|
||||||
export type RemoveFromGroup = z.infer<typeof removeFromGroupSchema>;
|
export type RemoveFromGroup = z.infer<typeof removeFromGroupSchema>;
|
||||||
|
export type ResetPassword = z.infer<typeof resetPasswordSchema>;
|
||||||
|
export type EnableUserAccount = z.infer<typeof enableUserAccountSchema>;
|
||||||
|
export type BulkEnableUserAccounts = z.infer<typeof bulkEnableUserAccountsSchema>;
|
||||||
export type DynamicGroupRule = typeof dynamicGroupRules.$inferSelect;
|
export type DynamicGroupRule = typeof dynamicGroupRules.$inferSelect;
|
||||||
export type InsertDynamicGroupRule = z.infer<typeof insertDynamicGroupRuleSchema>;
|
export type InsertDynamicGroupRule = z.infer<typeof insertDynamicGroupRuleSchema>;
|
||||||
export type DynamicGroupCondition = typeof dynamicGroupConditions.$inferSelect;
|
export type DynamicGroupCondition = typeof dynamicGroupConditions.$inferSelect;
|
||||||
@@ -651,22 +701,22 @@ export const ldapAttributesRelations = relations(ldapAttributes, ({ one }) => ({
|
|||||||
}));
|
}));
|
||||||
|
|
||||||
// Generate insertion schemas
|
// Generate insertion schemas
|
||||||
export const insertLdapFilterSchema = createInsertSchema(ldapFilters).omit({
|
export const insertLdapFilterSchema = createInsertSchema(ldapFilters).omit({
|
||||||
id: true,
|
id: true,
|
||||||
createdAt: true,
|
createdAt: true,
|
||||||
modifiedAt: true,
|
modifiedAt: true,
|
||||||
currentVersion: true
|
currentVersion: true
|
||||||
});
|
});
|
||||||
|
|
||||||
export const insertLdapFilterRevisionSchema = createInsertSchema(ldapFilterRevisions).omit({
|
export const insertLdapFilterRevisionSchema = createInsertSchema(ldapFilterRevisions).omit({
|
||||||
id: true,
|
id: true,
|
||||||
createdAt: true
|
createdAt: true
|
||||||
});
|
});
|
||||||
|
|
||||||
export const insertLdapAttributeSchema = createInsertSchema(ldapAttributes).omit({
|
export const insertLdapAttributeSchema = createInsertSchema(ldapAttributes).omit({
|
||||||
id: true,
|
id: true,
|
||||||
createdAt: true,
|
createdAt: true,
|
||||||
updatedAt: true
|
updatedAt: true
|
||||||
});
|
});
|
||||||
|
|
||||||
// Export types
|
// Export types
|
||||||
@@ -678,8 +728,8 @@ export type LdapAttribute = typeof ldapAttributes.$inferSelect;
|
|||||||
export type InsertLdapAttribute = z.infer<typeof insertLdapAttributeSchema>;
|
export type InsertLdapAttribute = z.infer<typeof insertLdapAttributeSchema>;
|
||||||
|
|
||||||
// Audit log schema and types
|
// Audit log schema and types
|
||||||
export const insertAuditLogSchema = createInsertSchema(auditLogs).omit({
|
export const insertAuditLogSchema = createInsertSchema(auditLogs).omit({
|
||||||
id: true,
|
id: true,
|
||||||
timestamp: true
|
timestamp: true
|
||||||
});
|
});
|
||||||
export type AuditLog = typeof auditLogs.$inferSelect;
|
export type AuditLog = typeof auditLogs.$inferSelect;
|
||||||
|
|||||||
Reference in New Issue
Block a user