Skip to content

Commit 95d401a

Browse files
committed
vmm-cli: Add basic auth
1 parent ad5598d commit 95d401a

File tree

2 files changed

+52
-4
lines changed

2 files changed

+52
-4
lines changed

vmm-cli-user-guide.md

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,8 @@ The VMM CLI is a single Python script (`vmm-cli.py`) that you can run directly:
3333

3434
By default, the CLI connects to `http://localhost:8080`. You can configure the server URL in several ways:
3535

36+
### Server URL Configuration
37+
3638
#### Environment Variable (Recommended)
3739

3840
Set the `DSTACK_VMM_URL` environment variable:
@@ -64,6 +66,30 @@ export DSTACK_VMM_URL=unix:/path/to/socket
6466

6567
**Priority Order:** Command line `--url` > `DSTACK_VMM_URL` environment variable > default `http://localhost:8080`
6668

69+
### Authentication
70+
71+
If your dstack-vmm server requires authentication, you can provide credentials using:
72+
73+
#### Environment Variables (Recommended)
74+
75+
```bash
76+
# Set authentication credentials
77+
export DSTACK_VMM_AUTH_USER=your-username
78+
export DSTACK_VMM_AUTH_PASSWORD=your-password
79+
80+
# Then use CLI normally
81+
./vmm-cli.py lsvm
82+
```
83+
84+
#### Command Line Arguments
85+
86+
```bash
87+
./vmm-cli.py --auth-user your-username --auth-password your-password lsvm
88+
```
89+
90+
**Note:** Environment variables take precedence over command line arguments for authentication.
91+
92+
6793
## Basic Commands
6894

6995
### List Virtual Machines
@@ -294,6 +320,10 @@ After successful deployment, verify your VM is running correctly:
294320
# Connect to local VMM instance
295321
export DSTACK_VMM_URL=http://127.0.0.1:12000
296322

323+
# If authentication is required
324+
export DSTACK_VMM_AUTH_USER=your-username
325+
export DSTACK_VMM_AUTH_PASSWORD=your-password
326+
297327
# Create a basic docker-compose.yml
298328
cat > docker-compose.yml << 'EOF'
299329
version: '3.8'

vmm/src/vmm-cli.py

Lines changed: 22 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
import http.client
1111
import urllib.parse
1212
import ssl
13+
import base64
1314

1415
from typing import Optional, Dict, List, Tuple, Union, BinaryIO, Any
1516

@@ -133,9 +134,11 @@ def connect(self):
133134
class VmmClient:
134135
"""A unified HTTP client that supports both regular HTTP and Unix Domain Sockets."""
135136

136-
def __init__(self, base_url: str):
137+
def __init__(self, base_url: str, auth_user: Optional[str] = None, auth_password: Optional[str] = None):
137138
self.base_url = base_url.rstrip('/')
138139
self.use_uds = self.base_url.startswith('unix:')
140+
self.auth_user = auth_user
141+
self.auth_password = auth_password
139142

140143
if self.use_uds:
141144
self.uds_path = self.base_url[5:] # Remove 'unix:' prefix
@@ -163,6 +166,13 @@ def request(self, method: str, path: str, headers: Dict[str, str] = None,
163166
if headers is None:
164167
headers = {}
165168

169+
# Add Basic Authentication header if credentials are provided
170+
if self.auth_user and self.auth_password:
171+
credentials = f"{self.auth_user}:{self.auth_password}"
172+
encoded_credentials = base64.b64encode(
173+
credentials.encode('utf-8')).decode('ascii')
174+
headers['Authorization'] = f'Basic {encoded_credentials}'
175+
166176
# Prepare the body
167177
if isinstance(body, dict):
168178
body = json.dumps(body).encode('utf-8')
@@ -214,12 +224,12 @@ def request(self, method: str, path: str, headers: Dict[str, str] = None,
214224

215225

216226
class VmmCLI:
217-
def __init__(self, base_url: str):
227+
def __init__(self, base_url: str, auth_user: Optional[str] = None, auth_password: Optional[str] = None):
218228
self.base_url = base_url.rstrip('/')
219229
self.headers = {
220230
'Content-Type': 'application/json'
221231
}
222-
self.client = VmmClient(base_url)
232+
self.client = VmmClient(base_url, auth_user, auth_password)
223233

224234
def rpc_call(self, method: str, params: Optional[Dict] = None) -> Dict:
225235
"""Make an RPC call to the dstack-vmm API"""
@@ -796,6 +806,14 @@ def main():
796806
parser.add_argument(
797807
'--url', default=default_url, help='dstack-vmm API URL (can also be set via DSTACK_VMM_URL env var)')
798808

809+
# Basic authentication arguments
810+
parser.add_argument(
811+
'--auth-user', default=os.environ.get('DSTACK_VMM_AUTH_USER'),
812+
help='Basic auth username (can also be set via DSTACK_VMM_AUTH_USER env var)')
813+
parser.add_argument(
814+
'--auth-password', default=os.environ.get('DSTACK_VMM_AUTH_PASSWORD'),
815+
help='Basic auth password (can also be set via DSTACK_VMM_AUTH_PASSWORD env var)')
816+
799817
subparsers = parser.add_subparsers(dest='command', help='Commands')
800818

801819
# List command
@@ -935,7 +953,7 @@ def main():
935953

936954
args = parser.parse_args()
937955

938-
cli = VmmCLI(args.url)
956+
cli = VmmCLI(args.url, args.auth_user, args.auth_password)
939957

940958
if args.command == 'lsvm':
941959
cli.list_vms(args.verbose)

0 commit comments

Comments
 (0)