# Local Development Environment

This directory contains configuration and scripts for running cluster-service-ng locally with a mock Dataplane Manager.

## Architecture

```
┌─────────────────────────────────────────────────────────────────────┐
│                          Host Machine                                │
│                                                                     │
│  ┌──────────────────────────────────────────┐                       │
│  │     Developer's IDE / Terminal           │                       │
│  │  ┌────────────────┐  ┌────────────────┐  │                       │
│  │  │cluster-service │  │   executor     │  │  ← Run binaries       │
│  │  │   :10000       │  │   :10002       │  │    locally            │
│  │  └───────┬────────┘  └───────┬────────┘  │                       │
│  └──────────┼───────────────────┼───────────┘                       │
│             │ gRPC              │ gRPC                               │
│             ▼                   ▼                                    │
│  ┌──────────┬───────────────────────────────────────────────────┐   │
│  │  MySQL   │  ┌────────────┐  ┌───────────────────────┐        │   │
│  │  :3306   │  │  Mock-DPM  │  │     kind cluster      │        │   │
│  │ (local)  │  │   :10001   │  │ (K8s + TiDB Operator) │        │   │
│  │          │  └────────────┘  └───────────────────────┘        │   │
│  └──────────┴───────────────────────────────────────────────────┘   │
└─────────────────────────────────────────────────────────────────────┘
```

## Prerequisites

- Docker and Docker Compose
- [kind](https://kind.sigs.k8s.io/) (Kubernetes IN Docker)
- Go 1.24+
- kubectl
- grpcurl (for testing)
- **Local MySQL server** (running on localhost:3306)

### Install Prerequisites

```bash
# macOS
brew install kind kubectl grpcurl

# Linux - kind
curl -Lo ./kind https://kind.sigs.k8s.io/dl/v0.26.0/kind-linux-amd64
chmod +x ./kind
sudo mv ./kind /usr/local/bin/kind

# Linux - grpcurl
go install github.com/fullstorydev/grpcurl/cmd/grpcurl@latest
```

## Quick Start

```bash
# 0. Ensure MySQL is running locally (localhost:3306, root user without password)
mysql -h 127.0.0.1 -u root -e "SELECT 1"

# 1. Start the local environment (mock-dpm, kind cluster, TiDB Operator)
cd hack/local-dev
make local-up

# 2. In terminal 1: Run the executor
go run ./cmd/executor --config hack/local-dev/executor-config.yaml

# 3. In terminal 2: Run cluster-service
go run ./cmd/cluster_ng_server --config hack/local-dev/config.yaml

# 4. In terminal 3: Test the APIs
cd hack/local-dev
make test-check
make test-list
```

## What Gets Deployed

| Component | Description |
|-----------|-------------|
| MySQL | **Local process** (not containerized) - Database for cluster-service-ng state |
| Mock-DPM | Mock Dataplane Manager (simulates cloud API) |
| Kind Cluster | Local K8s cluster for testing |
| TiDB Operator | v2.1.0-alpha.15 - reconciles TiDB CRs |
| CRDs | cluster-service-ng custom resources |

## Make Targets

### Environment Management

| Target | Description |
|--------|-------------|
| `make local-up` | Start mock-dpm, kind cluster, TiDB Operator (requires local MySQL) |
| `make local-down` | Stop and cleanup all services |
| `make local-logs` | View docker-compose logs |
| `make local-reset` | Reset mock-dpm state (clear in-memory data) |
| `make local-status` | Show status of all local services |
| `make local-mysql` | Connect to MySQL CLI |

### Testing

| Target | Description |
|--------|-------------|
| `make test-check` | Check if all services are running |
| `make test-create-sharedpool` | Create a test SharedPool |
| `make test-create-cluster` | Create a test TiDBCluster |
| `make test-delete-cluster` | Delete the test TiDBCluster |
| `make test-delete-sharedpool` | Delete the test SharedPool |
| `make test-list` | List all SharedPools and TiDBClusters |
| `make test-all` | Run all workflow tests |

## Services

### MySQL (Local Process)

- **Host**: localhost
- **Port**: 3306
- **User**: root
- **Password**: (empty)
- **Database**: dev_local_ng

> **Note**: MySQL runs as a local process on your machine, not in a container.

### Mock Dataplane Manager

A mock implementation of the dataplane-manager gRPC service. It simulates cloud resource creation without actually creating AWS/GCP/Azure resources.

- **gRPC Port**: 10001
- **Admin HTTP Port**: 8081

#### Admin Endpoints

| Endpoint | Method | Description |
|----------|--------|-------------|
| `/healthz` | GET | Health check |
| `/dump` | GET | Dump all stored data |
| `/reset` | POST | Clear all in-memory state |

```bash
curl http://localhost:8081/healthz
curl http://localhost:8081/dump | jq .
curl -X POST http://localhost:8081/reset
```

#### Implemented Services

- **DataPlaneService**: GetDataPlane, CreateDataPlane, ListDataPlanes, CreateNodePool, ListNodePools, DeleteNodePool, ListNodePoolConfigs
- **BucketService**: CreateBucket, GetBucket, ListBuckets, DeleteBucket, ApplyLifecycleRules, GetLifecycleRules
- **LoadBalancerService**: CreateLoadBalancer, GetLoadBalancer, UpdateLoadBalancer, DeleteLoadBalancer
- **PrivateLinkConnectionService**: CreatePrivateLinkService, GetPrivateLinkService, UpdatePrivateLinkService, DeletePrivateLinkService

### TiDB Operator

TiDB Operator v2.1.0-alpha.15 is deployed in the `tidb-admin` namespace. It will reconcile TiDB-related CRs created by cluster-service-ng.

```bash
# Check TiDB Operator status
kubectl -n tidb-admin get pods

# View TiDB Operator logs
kubectl -n tidb-admin logs -f deployment/tidb-controller-manager
```

### Cluster Service

- **gRPC Port**: 10000
- **HTTP Port**: 8080
- **Metrics Port**: 9090

### Executor

- **gRPC Port**: 10002
- **Metrics Port**: 9092

## Testing Workflows

### Manual Testing with grpcurl

```bash
# List services
grpcurl -plaintext localhost:10000 list

# Create SharedPool
grpcurl -plaintext -d '{
  "shared_pool": {"id": "sp-001", "dataplane_name": "dp-001"},
  "request_unit": {"min": 1000, "max": 10000},
  "init_shared_pool_config": {
    "tikv_data_storage": {"storage_class": "gp3", "storage_size_gi": 100},
    "tikv_raftlog_storage": {"storage_class": "gp3", "storage_size_gi": 50},
    "tiflash_cn_storage": {"storage_class": "gp3", "storage_size_gi": 100},
    "tiflash_wn_storage": {"storage_class": "gp3", "storage_size_gi": 100}
  },
  "tenant_id": "tenant-001"
}' localhost:10000 cluster_service_ng.v1beta.SharedPoolService/CreateSharedPool

# List SharedPools
grpcurl -plaintext -d '{}' localhost:10000 cluster_service_ng.v1beta.SharedPoolService/ListSharedPools

# Create TiDBCluster
grpcurl -plaintext -d '{
  "id": "cluster-001",
  "tenant_id": "tenant-001",
  "shared_pool_id": "sp-001",
  "request_unit": {"min": 1000, "max": 5000},
  "gateway_identity": "gw-001"
}' localhost:10000 cluster_service_ng.v1beta.TiDBClusterService/CreateTiDBCluster

# List TiDBClusters
grpcurl -plaintext -d '{}' localhost:10000 cluster_service_ng.v1beta.TiDBClusterService/ListTiDBClusters
```

### Using Test Script

```bash
cd hack/local-dev

# Run all tests
./scripts/test-workflows.sh all

# Or run individual tests
./scripts/test-workflows.sh create-sharedpool
./scripts/test-workflows.sh create-cluster
./scripts/test-workflows.sh list-clusters
./scripts/test-workflows.sh delete-cluster
./scripts/test-workflows.sh delete-sharedpool
```

## Troubleshooting

### MySQL connection refused

```bash
# Ensure local MySQL is running
mysql -h 127.0.0.1 -u root -e "SELECT 1"

# Create database if missing
mysql -h 127.0.0.1 -u root -e "CREATE DATABASE IF NOT EXISTS dev_local_ng"
```

### Mock-DPM not responding

```bash
# Check logs
docker logs csng-mock-dpm

# Check health
curl http://localhost:8081/healthz
```

### TiDB Operator issues

```bash
# Check operator pods
kubectl -n tidb-admin get pods

# Check operator logs
kubectl -n tidb-admin logs -f deployment/tidb-controller-manager

# Reinstall operator
kubectl apply -f https://github.com/pingcap/tidb-operator/releases/download/v2.1.0-alpha.15/tidb-operator.yaml --server-side
```

### cluster-service startup errors

```bash
# Check if MySQL is accessible
mysql -h 127.0.0.1 -u root -e "SELECT 1"

# Check if mock-dpm is accessible
grpcurl -plaintext localhost:10001 list
```

### Kind cluster issues

```bash
# Check cluster status
kubectl cluster-info

# Recreate cluster
kind delete cluster --name csng-dev
make local-up
```

## File Structure

```
hack/local-dev/
├── Makefile              # Make targets for local dev
├── README.md             # This file
├── config.yaml           # cluster-service config
├── executor-config.yaml  # executor config
├── docker-compose.yaml   # Docker services (mock-dpm only)
├── kind-config.yaml      # Kind cluster config
├── scripts/
│   └── test-workflows.sh # Test script for workflows
└── docs/
    └── ...
```

## Scope & Limitations

### What Works
- SharedPool CRUD workflows
- TiDBCluster CRUD workflows  
- TiDBGroup CRUD workflows
- TiDB Operator reconciliation of CRs
- Mock cloud resource creation (NodePool, Bucket, LoadBalancer)

### What Doesn't Work
- Actual TiDB pods won't start (no real nodes/resources)
- Backup/Restore workflows (need real S3/MinIO)
- TiCI/TiFlash (need real object storage)
- Audit logs (need real S3)

### For Full E2E Testing
If you need to test backup/restore or TiFlash, add MinIO:

```yaml
# Add to docker-compose.yaml
minio:
  image: minio/minio:latest
  ports:
    - "9000:9000"
    - "9001:9001"
  environment:
    MINIO_ROOT_USER: minioadmin
    MINIO_ROOT_PASSWORD: minioadmin
  command: server /data --console-address ":9001"
```
