Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
42 commits
Select commit Hold shift + click to select a range
99d38fb
Create README
Vanshika-Mittal Feb 5, 2026
07c7faf
Create Task-1.md
Vanshika-Mittal Feb 5, 2026
848529e
feat(auth) : added jwt authentication
Ds0uz4 Mar 17, 2026
58768bd
feat: project scaffold with dependencies
DevanshSharma351 Mar 20, 2026
900637f
feat: containers app scaffold
DevanshSharma351 Mar 20, 2026
caf57e5
feat: configure settings, ASGI, and Channels
DevanshSharma351 Mar 20, 2026
8cdaa4e
feat: dummy auth layer and docker client factory
DevanshSharma351 Mar 20, 2026
2e0898a
fix (auth) : splitting into different apps
Ds0uz4 Mar 25, 2026
96f0b0a
feat(registry) : Registry credentials store
Ds0uz4 Mar 25, 2026
f8a754c
feat(app) : Image pulling system
Ds0uz4 Mar 25, 2026
f10da57
feat: service layer - container CRUD, lifecycle, stats, logs, exec ti…
DevanshSharma351 Mar 25, 2026
44b44a4
test: model tests for Host, ContainerRecord, LifecycleEvent, ExecTicket
DevanshSharma351 Mar 25, 2026
b70fdd8
test: fix conftest, all unit and integration tests passing, created t…
DevanshSharma351 Mar 25, 2026
79edeb8
feat: add registry management and automated image build pipeline
Mar 26, 2026
da87149
feat: add image gallery UI with deploy action and complete registry &…
Mar 26, 2026
837f7c6
fix(auth): improve error handling for Docker API in container creation
Mar 26, 2026
370bafd
feat: all views, urls wired up and server running
DevanshSharma351 Mar 26, 2026
d8cc340
feat: exec and log tail WebSocket consumers with ticket auth
DevanshSharma351 Mar 26, 2026
681e854
everythings works; made minor frontend, will be replaced soon by pari…
DevanshSharma351 Mar 27, 2026
baf6070
basic frontend, will be replaced by Pari
DevanshSharma351 Mar 27, 2026
c0134bc
chore: remove Task-1 from module2
DevanshSharma351 Mar 27, 2026
7213c43
update(backend)- to fetch images properly
DevanshSharma351 Mar 29, 2026
3b94c61
feat(hosts): add CRUD API and role-based access control
neha-jain-2636 Mar 27, 2026
7fd016e
Merge branch 'authentication' into module1/core-setup
Ds0uz4 Mar 30, 2026
a30d3d9
feat(frontend):add authetication pages, dashboard and role assignment
neha-jain-2636 Mar 31, 2026
883fe78
feat(module2): align with team main template and finalize containers …
DevanshSharma351 Apr 1, 2026
54b50b6
merge(module1): integrate core-setup into module2 with auth-aligned c…
DevanshSharma351 Apr 1, 2026
2aa8951
chore(history): preserve original module2 commit lineage
DevanshSharma351 Apr 1, 2026
2a431dd
feat(module2): improve container dashboard UX
DevanshSharma351 Apr 1, 2026
34aae1e
feat(core): integrate RBAC, container lifecycle and image management
neha-jain-2636 Apr 6, 2026
d74569d
fix(db): mismatch in db
Ds0uz4 Apr 7, 2026
1716c3e
fix(modules): dedupe hosts and sync container list to selected host
DevanshSharma351 Apr 7, 2026
cab7f88
chore(security): sanitize test secrets and env placeholders
DevanshSharma351 Apr 7, 2026
d94e41a
fix(host) : makemigrations issue
Ds0uz4 Apr 7, 2026
cb93b8b
fix(rbac, frontend): Fix local admin/host image permissions and surfa…
AppajiDheeraj Apr 7, 2026
a09b7a8
fix (.gitignore)
AppajiDheeraj Apr 7, 2026
78a6a63
Merge branch 'module1/core-setup' of https://github.com/WebClub-NITK/…
AppajiDheeraj Apr 7, 2026
b7207d0
Fix assigned host-role container manage/delete access
DevanshSharma351 Apr 8, 2026
4282151
Fix container refresh host id and assigned image list access
DevanshSharma351 Apr 8, 2026
fb3c91b
Align image permissions with host assignments
DevanshSharma351 Apr 8, 2026
516f290
feat(networks): add network-container attachment feature
neha-jain-2636 Jun 11, 2026
d0ccc64
feat: add stacks/compose module to backend
DevanshSharma351 Jul 8, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 18 additions & 0 deletions .env.example
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
# Django
DJANGO_DEBUG=true
DJANGO_ALLOWED_HOSTS=127.0.0.1,localhost

# 32 url-safe base64-encoded bytes for Fernet (generate with: python -c "from cryptography.fernet import Fernet; print(Fernet.generate_key().decode())")
FIELD_ENCRYPTION_KEY=REPLACE_ME_WITH_FERNET_KEY

# Postgres
POSTGRES_DB=docker_integration
POSTGRES_USER=postgres
POSTGRES_PASSWORD=CHANGE_ME_POSTGRES_PASSWORD
POSTGRES_HOST=localhost
POSTGRES_PORT=5432

# pgAdmin
PGADMIN_PORT=5050
PGADMIN_DEFAULT_EMAIL=admin@example.com
PGADMIN_DEFAULT_PASSWORD=CHANGE_ME_PGADMIN_PASSWORD
38 changes: 30 additions & 8 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,26 +1,48 @@
# Backend
# Python virtual environments
venv/
.venv/
backend/venv/
backend/.venv/

# Python cache
__pycache__/
*.py[cod]

# Node dependencies
node_modules/
frontend/node_modules/

# Build output
dist/
dist-ssr/

# Frontend
logs
# Logs
logs/
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*
pnpm-debug.log*
lerna-debug.log*

node_modules
dist
dist-ssr
# Environment files
.env
*.local

# Local databases
db.*
backend/db.*

# Editor and OS
.vscode/*
!.vscode/extensions.json
.idea
.idea/
.DS_Store
*.suo
*.ntvs*
*.njsproj
*.sln
*.sw?
*.sw?

# Tool caches
*.cache
85 changes: 58 additions & 27 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,67 +1,98 @@
# Docker Integration Host

**Docker Integration Host** is a powerful orchestration tool designed to manage multiple containers and networks across different hosts from a single, centralized interface. It aims to simplify the complexity of distributed container management, providing a unified platform for monitoring, scaling, and configuring your Docker infrastructure.
A full-stack Docker Management Dashboard built with Django REST Framework (Backend) and React (Frontend). This application allows you to remotely manage Docker hosts, pull/push images, monitor containers, and manage role-based access controls across your infrastructure.

## Features
## Project Structure

- **Single Host Management**: Orchestrate containers across multiple remote hosts.
- **Network Orchestration**: Manage and bridge networks between different Docker environments.
- **Centralized Control**: Unified dashboard for viewing and controlling container lifecycles.
The repository is split into two independent modules:
- `backend/`: Django API server providing endpoints for Docker SDK integration, database persistence, and RBAC authentication.
- `frontend/`: React single-page application serving the dashboard UI.

## Getting Started
---

### Backend Setup (Django)
## Local Setup Guidelines

The backend handles the orchestration logic, communication with remote Docker hosts, and state management.
### Prerequisites
- Python 3.10+
- Node.js 18+
- Docker Engine locally installed and running (for local container management endpoints)
- Git

1. **Navigate to the backend directory:**
### 1. Backend Setup (Django)

Open your terminal and navigate to the project root:

1. **Change to the backend directory**
```bash
cd backend
```

2. **Create and activate a virtual environment:**
2. **Create and activate a Python virtual environment**
- Windows:
```bash
python -m venv venv
.\venv\Scripts\activate
```
- macOS / Linux:
```bash
python3 -m venv venv
source venv/bin/activate
```

3. **Install the required dependencies**
```bash
python -m venv venv
source venv/bin/activate # On Windows: venv\Scripts\activate
pip install -r requirements.txt
```

3. **Install dependencies:**
4. **Run Database Migrations**
Initialize the SQLite database schema:
```bash
pip install -r requirements.txt
python manage.py migrate
```

4. **Run database migrations:**
5. **Create a Superuser** (Required to access all features & bypass RBAC limitations out-of-the-box):
```bash
python manage.py migrate
python manage.py createsuperuser
```

5. **Start the Django development server:**
6. **Start the Development Server**
```bash
python manage.py runserver
```
The backend will be running at `http://localhost:8000`.
*The API will be available at `http://127.0.0.1:8000/`*

---

### Frontend Setup (Vite + React)
### 2. Frontend Setup (React)

The frontend provides the user interface for managing your containers and network configurations.
Open a **new, separate terminal tab/window** and navigate to the project root:

1. **Navigate to the frontend directory:**
1. **Change to the frontend directory**
```bash
cd frontend
```

2. **Install dependencies:**
2. **Install node dependencies**
```bash
npm install
```

3. **Start the development server:**
3. **Start the Development Server**
```bash
npm run dev
```
The frontend will be running at `http://localhost:5173`.
*The React dashboard will be accessible at the Localhost URL provided in the terminal (usually `http://localhost:5173`).*

---

## Post-Setup Verification

1. Head to your frontend dashboard URL in the browser.
2. Login using the Superuser credentials you just generated.
3. **Module 1 (RBAC & Auth):** Confirm your user role functions properly, and try assigning hosts.
4. **Module 2 (Containers):** Verify you can list, stop, and boot containers directly from your dashboard.
5. **Module 3 (Images):** Switch over to the Images tab to pull real images from registries seamlessly using the background queue jobs!

## Architecture
## Important Notes for Windows Users

- **Backend**: Django REST Framework
- **Frontend**: React with Vite and Tailwind CSS
A platform-specific handler is automatically enabled within `backend/containers/models.py`. If you define "local-docker" as your host, the Docker daemon socket transparently defaults to `npipe:////./pipe/docker_engine`, meaning everything connects naturally without Unix socket errors! Make sure Docker Desktop is open and running in the background before testing the UI.
16 changes: 15 additions & 1 deletion backend/authentication/admin.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,17 @@
from django.contrib import admin
from django.contrib.auth.admin import UserAdmin
from django.contrib.auth import get_user_model

# Register your models here.
User = get_user_model()


@admin.register(User)
class CustomUserAdmin(UserAdmin):
list_display = ['username', 'email', 'role', 'is_staff', 'is_active']
list_filter = ['role', 'is_staff', 'is_active']
fieldsets = UserAdmin.fieldsets + (
('Role', {'fields': ('role',)}),
)
add_fieldsets = UserAdmin.add_fieldsets + (
('Role', {'fields': ('role',)}),
)
1 change: 1 addition & 0 deletions backend/authentication/apps.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,5 @@


class AuthenticationConfig(AppConfig):
default_auto_field = 'django.db.models.BigAutoField'
name = 'authentication'
45 changes: 45 additions & 0 deletions backend/authentication/migrations/0001_initial.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
# Generated migration for custom User model with role field

from django.db import migrations, models
import django.contrib.auth.models
import django.contrib.auth.validators
import django.utils.timezone


class Migration(migrations.Migration):

initial = True

dependencies = [
('auth', '0012_alter_user_first_name_max_length'),
]

operations = [
migrations.CreateModel(
name='User',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('password', models.CharField(max_length=128, verbose_name='password')),
('last_login', models.DateTimeField(blank=True, null=True, verbose_name='last login')),
('is_superuser', models.BooleanField(default=False, help_text='Designates that this user has all permissions without explicitly assigning them.', verbose_name='superuser status')),
('username', models.CharField(error_messages={'unique': 'A user with that username already exists.'}, help_text='Required. 150 characters or fewer. Letters, digits and @/./+/-/_ only.', max_length=150, unique=True, validators=[django.contrib.auth.validators.UnicodeUsernameValidator()], verbose_name='username')),
('first_name', models.CharField(blank=True, max_length=150, verbose_name='first name')),
('last_name', models.CharField(blank=True, max_length=150, verbose_name='last name')),
('email', models.EmailField(blank=True, max_length=254, verbose_name='email address')),
('is_staff', models.BooleanField(default=False, help_text='Designates whether the user can log into this admin site.', verbose_name='staff status')),
('is_active', models.BooleanField(default=True, help_text='Designates whether this user should be treated as active. Unselect this instead of deleting accounts.', verbose_name='active')),
('date_joined', models.DateTimeField(default=django.utils.timezone.now, verbose_name='date joined')),
('role', models.CharField(choices=[('admin', 'Admin'), ('host', 'Host'), ('viewer', 'Viewer')], default='viewer', max_length=10)),
('groups', models.ManyToManyField(blank=True, help_text='The groups this user belongs to. A user will get all permissions granted to each of their groups.', related_name='user_set', related_query_name='user', to='auth.group', verbose_name='groups')),
('user_permissions', models.ManyToManyField(blank=True, help_text='Specific permissions for this user.', related_name='user_set', related_query_name='user', to='auth.permission', verbose_name='user permissions')),
],
options={
'verbose_name': 'user',
'verbose_name_plural': 'users',
'abstract': False,
},
managers=[
('objects', django.contrib.auth.models.UserManager()),
],
),
]
28 changes: 27 additions & 1 deletion backend/authentication/models.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,29 @@
from django.contrib.auth.models import AbstractUser, UserManager
from django.db import models

# Create your models here.

class CustomUserManager(UserManager):
def create_superuser(self, username, email=None, password=None, **extra_fields):
extra_fields.setdefault("is_staff", True)
extra_fields.setdefault("is_superuser", True)
extra_fields.setdefault("role", User.ADMIN)
return super().create_superuser(username, email, password, **extra_fields)


class User(AbstractUser):
ADMIN = 'admin'
HOST = 'host'
VIEWER = 'viewer'

ROLE_CHOICES = [
(ADMIN, 'Admin'),
(HOST, 'Host'),
(VIEWER, 'Viewer'),
]

role = models.CharField(max_length=10, choices=ROLE_CHOICES, default=VIEWER)

objects = CustomUserManager()

def __str__(self):
return f"{self.username} ({self.role})"
16 changes: 16 additions & 0 deletions backend/authentication/permissions.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
from rest_framework import permissions


class IsAdmin(permissions.BasePermission):
def has_permission(self, request, view):
return request.user.is_authenticated and request.user.role == 'admin'


class IsHost(permissions.BasePermission):
def has_permission(self, request, view):
return request.user.is_authenticated and request.user.role in ['admin', 'host']


class IsViewer(permissions.BasePermission):
def has_permission(self, request, view):
return request.user.is_authenticated and request.user.role in ['admin', 'host', 'viewer']
31 changes: 31 additions & 0 deletions backend/authentication/serializers.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
from rest_framework import serializers
from django.contrib.auth import get_user_model

User = get_user_model()


class UserSerializer(serializers.ModelSerializer):
bio = serializers.CharField(source='profile.bio', read_only=True)
avatar_url = serializers.CharField(source='profile.avatar_url', read_only=True)

class Meta:
model = User
fields = ['id', 'username', 'email', 'bio', 'avatar_url', 'role', 'is_superuser']

class RegisterSerializer(serializers.ModelSerializer):
password = serializers.CharField(write_only=True, min_length=8)

class Meta:
model = User
fields = ['username', 'email', 'password', 'role', 'first_name', 'last_name']

def create(self, validated_data):
user = User.objects.create_user(
username=validated_data['username'],
email=validated_data.get('email', ''),
password=validated_data['password'],
role=validated_data.get('role', User.VIEWER),
first_name=validated_data.get('first_name', ''),
last_name=validated_data.get('last_name', '')
)
return user
Loading