@magpiecloud/mags 1.8.13 → 1.8.15
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +95 -378
- package/bin/mags.js +196 -104
- package/index.js +6 -52
- package/package.json +22 -4
- package/API.md +0 -388
- package/Mags-API.postman_collection.json +0 -374
- package/QUICKSTART.md +0 -295
- package/deploy-page.sh +0 -171
- package/mags +0 -0
- package/mags.sh +0 -270
- package/nodejs/README.md +0 -197
- package/nodejs/bin/mags.js +0 -1146
- package/nodejs/index.js +0 -642
- package/nodejs/package.json +0 -42
- package/python/INTEGRATION.md +0 -800
- package/python/README.md +0 -161
- package/python/dist/magpie_mags-1.3.5-py3-none-any.whl +0 -0
- package/python/dist/magpie_mags-1.3.5.tar.gz +0 -0
- package/python/examples/demo.py +0 -181
- package/python/pyproject.toml +0 -39
- package/python/src/magpie_mags.egg-info/PKG-INFO +0 -182
- package/python/src/magpie_mags.egg-info/SOURCES.txt +0 -9
- package/python/src/magpie_mags.egg-info/dependency_links.txt +0 -1
- package/python/src/magpie_mags.egg-info/requires.txt +0 -1
- package/python/src/magpie_mags.egg-info/top_level.txt +0 -1
- package/python/src/mags/__init__.py +0 -6
- package/python/src/mags/client.py +0 -573
- package/python/test_sdk.py +0 -78
- package/skill.md +0 -153
- package/website/api.html +0 -1095
- package/website/claude-skill.html +0 -481
- package/website/cookbook/hn-marketing.html +0 -410
- package/website/cookbook/hn-marketing.sh +0 -42
- package/website/cookbook.html +0 -282
- package/website/env.js +0 -4
- package/website/index.html +0 -801
- package/website/llms.txt +0 -334
- package/website/login.html +0 -108
- package/website/mags.md +0 -210
- package/website/script.js +0 -453
- package/website/styles.css +0 -908
- package/website/tokens.html +0 -169
- package/website/usage.html +0 -185
package/python/README.md
DELETED
|
@@ -1,161 +0,0 @@
|
|
|
1
|
-
# Mags Python SDK
|
|
2
|
-
|
|
3
|
-
Execute scripts on [Magpie's](https://mags.run) instant VM infrastructure from Python.
|
|
4
|
-
|
|
5
|
-
## Install
|
|
6
|
-
|
|
7
|
-
```bash
|
|
8
|
-
pip install magpie-mags
|
|
9
|
-
```
|
|
10
|
-
|
|
11
|
-
## Quick Start
|
|
12
|
-
|
|
13
|
-
```python
|
|
14
|
-
from mags import Mags
|
|
15
|
-
|
|
16
|
-
m = Mags(api_token="your-token")
|
|
17
|
-
|
|
18
|
-
# Run a script and wait for the result
|
|
19
|
-
result = m.run_and_wait("echo 'Hello from a VM!'")
|
|
20
|
-
print(result["status"]) # "completed"
|
|
21
|
-
print(result["exit_code"]) # 0
|
|
22
|
-
for log in result["logs"]:
|
|
23
|
-
print(log["message"])
|
|
24
|
-
```
|
|
25
|
-
|
|
26
|
-
## Authentication
|
|
27
|
-
|
|
28
|
-
Pass `api_token` directly, or set one of these environment variables:
|
|
29
|
-
|
|
30
|
-
```bash
|
|
31
|
-
export MAGS_API_TOKEN="your-token"
|
|
32
|
-
# or
|
|
33
|
-
export MAGS_TOKEN="your-token"
|
|
34
|
-
```
|
|
35
|
-
|
|
36
|
-
## Usage
|
|
37
|
-
|
|
38
|
-
### Run a Script
|
|
39
|
-
|
|
40
|
-
```python
|
|
41
|
-
# Fire-and-forget
|
|
42
|
-
job = m.run("apt install -y ffmpeg && ffmpeg -version")
|
|
43
|
-
print(job["request_id"])
|
|
44
|
-
|
|
45
|
-
# Run and wait for completion
|
|
46
|
-
result = m.run_and_wait(
|
|
47
|
-
"python3 -c 'print(sum(range(100)))'",
|
|
48
|
-
timeout=30,
|
|
49
|
-
)
|
|
50
|
-
```
|
|
51
|
-
|
|
52
|
-
### Persistent Workspaces
|
|
53
|
-
|
|
54
|
-
```python
|
|
55
|
-
# First run: creates the workspace
|
|
56
|
-
m.run_and_wait(
|
|
57
|
-
"pip install pandas && echo 'setup done'",
|
|
58
|
-
workspace_id="my-project",
|
|
59
|
-
persistent=True,
|
|
60
|
-
)
|
|
61
|
-
|
|
62
|
-
# Second run: reuses the workspace (pandas is already installed)
|
|
63
|
-
m.run_and_wait(
|
|
64
|
-
"python3 -c 'import pandas; print(pandas.__version__)'",
|
|
65
|
-
workspace_id="my-project",
|
|
66
|
-
)
|
|
67
|
-
```
|
|
68
|
-
|
|
69
|
-
### Always-On VMs
|
|
70
|
-
|
|
71
|
-
```python
|
|
72
|
-
# VM that never auto-sleeps — stays running 24/7
|
|
73
|
-
job = m.run(
|
|
74
|
-
"python3 server.py",
|
|
75
|
-
workspace_id="my-api",
|
|
76
|
-
persistent=True,
|
|
77
|
-
no_sleep=True,
|
|
78
|
-
)
|
|
79
|
-
# Auto-recovers if the host goes down
|
|
80
|
-
```
|
|
81
|
-
|
|
82
|
-
### Enable URL / SSH Access
|
|
83
|
-
|
|
84
|
-
```python
|
|
85
|
-
job = m.run("python3 -m http.server 8080", persistent=True)
|
|
86
|
-
|
|
87
|
-
# HTTP access
|
|
88
|
-
access = m.enable_access(job["request_id"], port=8080)
|
|
89
|
-
print(access["url"])
|
|
90
|
-
|
|
91
|
-
# SSH access
|
|
92
|
-
ssh = m.enable_access(job["request_id"], port=22)
|
|
93
|
-
print(f"ssh root@{ssh['ssh_host']} -p {ssh['ssh_port']}")
|
|
94
|
-
```
|
|
95
|
-
|
|
96
|
-
### Upload Files
|
|
97
|
-
|
|
98
|
-
```python
|
|
99
|
-
file_ids = m.upload_files(["data.csv", "config.json"])
|
|
100
|
-
result = m.run_and_wait(
|
|
101
|
-
"ls /uploads && wc -l /uploads/data.csv",
|
|
102
|
-
file_ids=file_ids,
|
|
103
|
-
)
|
|
104
|
-
```
|
|
105
|
-
|
|
106
|
-
### Cron Jobs
|
|
107
|
-
|
|
108
|
-
```python
|
|
109
|
-
cron = m.cron_create(
|
|
110
|
-
name="nightly-backup",
|
|
111
|
-
cron_expression="0 0 * * *",
|
|
112
|
-
script="tar czf /workspace/backup.tar.gz /data",
|
|
113
|
-
workspace_id="backups",
|
|
114
|
-
)
|
|
115
|
-
|
|
116
|
-
jobs = m.cron_list()
|
|
117
|
-
m.cron_update(cron["id"], enabled=False)
|
|
118
|
-
m.cron_delete(cron["id"])
|
|
119
|
-
```
|
|
120
|
-
|
|
121
|
-
### Check Usage
|
|
122
|
-
|
|
123
|
-
```python
|
|
124
|
-
usage = m.usage(window_days=7)
|
|
125
|
-
print(f"Jobs: {usage['total_jobs']}, VM seconds: {usage['vm_seconds']:.0f}")
|
|
126
|
-
```
|
|
127
|
-
|
|
128
|
-
## API Reference
|
|
129
|
-
|
|
130
|
-
| Method | Description |
|
|
131
|
-
|--------|-------------|
|
|
132
|
-
| `run(script, **opts)` | Submit a job (`persistent`, `no_sleep`, `workspace_id`, ...) |
|
|
133
|
-
| `run_and_wait(script, **opts)` | Submit and block until done |
|
|
134
|
-
| `new(name, **opts)` | Create a VM sandbox (`persistent=True` for S3) |
|
|
135
|
-
| `find_job(name_or_id)` | Find a running/sleeping job by name or workspace |
|
|
136
|
-
| `exec(name_or_id, command)` | Run a command on an existing VM via SSH |
|
|
137
|
-
| `stop(name_or_id)` | Stop a running job |
|
|
138
|
-
| `url(name_or_id, port)` | Enable public URL and return full URL |
|
|
139
|
-
| `resize(workspace, disk_gb)` | Resize a workspace's disk |
|
|
140
|
-
| `status(request_id)` | Get job status |
|
|
141
|
-
| `logs(request_id)` | Get job logs |
|
|
142
|
-
| `list_jobs(page, page_size)` | List recent jobs |
|
|
143
|
-
| `update_job(request_id, **opts)` | Update job config (`startup_command`, `no_sleep`) |
|
|
144
|
-
| `enable_access(request_id, port)` | Enable URL or SSH access |
|
|
145
|
-
| `usage(window_days)` | Get usage summary |
|
|
146
|
-
| `upload_file(path)` | Upload a file, returns file ID |
|
|
147
|
-
| `upload_files(paths)` | Upload multiple files |
|
|
148
|
-
| `url_alias_create(sub, ws_id)` | Create a stable URL alias |
|
|
149
|
-
| `url_alias_list()` | List URL aliases |
|
|
150
|
-
| `url_alias_delete(sub)` | Delete a URL alias |
|
|
151
|
-
| `cron_create(**opts)` | Create a cron job |
|
|
152
|
-
| `cron_list()` | List cron jobs |
|
|
153
|
-
| `cron_get(id)` | Get a cron job |
|
|
154
|
-
| `cron_update(id, **updates)` | Update a cron job |
|
|
155
|
-
| `cron_delete(id)` | Delete a cron job |
|
|
156
|
-
|
|
157
|
-
## Links
|
|
158
|
-
|
|
159
|
-
- Website: [mags.run](https://mags.run)
|
|
160
|
-
- Node.js SDK: `npm install @magpiecloud/mags`
|
|
161
|
-
- CLI: `npm install -g @magpiecloud/mags`
|
|
Binary file
|
|
Binary file
|
package/python/examples/demo.py
DELETED
|
@@ -1,181 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env python3
|
|
2
|
-
"""
|
|
3
|
-
Mags Python SDK - Usage Examples
|
|
4
|
-
|
|
5
|
-
Set your API token before running:
|
|
6
|
-
export MAGS_API_TOKEN="your-token-here"
|
|
7
|
-
|
|
8
|
-
Then:
|
|
9
|
-
pip install -e ../ # install the SDK locally
|
|
10
|
-
python demo.py # run all examples
|
|
11
|
-
python demo.py quick # run just the quick example
|
|
12
|
-
python demo.py workspace # run the workspace example
|
|
13
|
-
python demo.py url # run the URL access example
|
|
14
|
-
python demo.py cron # run the cron example
|
|
15
|
-
python demo.py usage # check usage stats
|
|
16
|
-
"""
|
|
17
|
-
|
|
18
|
-
import sys
|
|
19
|
-
import time
|
|
20
|
-
|
|
21
|
-
from mags import Mags
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
def quick_run(m: Mags):
|
|
25
|
-
"""Run a simple script and get the output."""
|
|
26
|
-
print("=== Quick Run ===")
|
|
27
|
-
result = m.run_and_wait(
|
|
28
|
-
"echo 'Hello from Mags!' && uname -a && python3 --version",
|
|
29
|
-
timeout=30,
|
|
30
|
-
)
|
|
31
|
-
print(f"Status: {result['status']}")
|
|
32
|
-
print(f"Exit code: {result['exit_code']}")
|
|
33
|
-
print(f"Duration: {result['duration_ms']}ms")
|
|
34
|
-
print("Logs:")
|
|
35
|
-
for log in result["logs"]:
|
|
36
|
-
print(f" [{log['source']}] {log['message']}")
|
|
37
|
-
print()
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
def workspace_example(m: Mags):
|
|
41
|
-
"""Demonstrate persistent workspaces."""
|
|
42
|
-
print("=== Persistent Workspace ===")
|
|
43
|
-
ws = "python-sdk-demo"
|
|
44
|
-
|
|
45
|
-
# First run: install something
|
|
46
|
-
print(f"1. Setting up workspace '{ws}'...")
|
|
47
|
-
result = m.run_and_wait(
|
|
48
|
-
"pip install cowsay && echo 'setup done'",
|
|
49
|
-
workspace_id=ws,
|
|
50
|
-
persistent=True,
|
|
51
|
-
timeout=60,
|
|
52
|
-
)
|
|
53
|
-
print(f" Setup: {result['status']} (exit={result['exit_code']})")
|
|
54
|
-
|
|
55
|
-
# Second run: use what we installed (it persists!)
|
|
56
|
-
print(f"2. Running in existing workspace '{ws}'...")
|
|
57
|
-
result = m.run_and_wait(
|
|
58
|
-
"python3 -c \"import cowsay; cowsay.cow('Mags Python SDK!')\"",
|
|
59
|
-
workspace_id=ws,
|
|
60
|
-
timeout=30,
|
|
61
|
-
)
|
|
62
|
-
print(f" Result: {result['status']} (exit={result['exit_code']})")
|
|
63
|
-
for log in result["logs"]:
|
|
64
|
-
if log["source"] == "stdout":
|
|
65
|
-
print(f" {log['message']}")
|
|
66
|
-
print()
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
def url_access_example(m: Mags):
|
|
70
|
-
"""Start a web server and get its public URL."""
|
|
71
|
-
print("=== URL Access ===")
|
|
72
|
-
|
|
73
|
-
# Start a persistent job with a web server
|
|
74
|
-
job = m.run(
|
|
75
|
-
"echo '<h1>Hello from Mags!</h1>' > /tmp/index.html && "
|
|
76
|
-
"cd /tmp && python3 -m http.server 8080",
|
|
77
|
-
persistent=True,
|
|
78
|
-
name="python-sdk-webserver",
|
|
79
|
-
)
|
|
80
|
-
request_id = job["request_id"]
|
|
81
|
-
print(f"Job submitted: {request_id}")
|
|
82
|
-
|
|
83
|
-
# Wait for it to start running
|
|
84
|
-
print("Waiting for VM to start...")
|
|
85
|
-
for _ in range(20):
|
|
86
|
-
s = m.status(request_id)
|
|
87
|
-
if s["status"] == "running":
|
|
88
|
-
break
|
|
89
|
-
time.sleep(1)
|
|
90
|
-
|
|
91
|
-
# Enable URL access
|
|
92
|
-
access = m.enable_access(request_id, port=8080)
|
|
93
|
-
print(f"URL: {access.get('url', 'N/A')}")
|
|
94
|
-
print(f"Access type: {access['access_type']}")
|
|
95
|
-
|
|
96
|
-
# Enable SSH access
|
|
97
|
-
ssh = m.enable_access(request_id, port=22)
|
|
98
|
-
print(f"SSH: ssh root@{ssh['ssh_host']} -p {ssh['ssh_port']}")
|
|
99
|
-
print()
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
def cron_example(m: Mags):
|
|
103
|
-
"""Create, list, and clean up a cron job."""
|
|
104
|
-
print("=== Cron Jobs ===")
|
|
105
|
-
|
|
106
|
-
# Create a cron job
|
|
107
|
-
cron = m.cron_create(
|
|
108
|
-
name="sdk-test-cron",
|
|
109
|
-
cron_expression="0 * * * *", # every hour
|
|
110
|
-
script="echo 'cron tick' && date",
|
|
111
|
-
)
|
|
112
|
-
print(f"Created cron job: {cron['id']} ({cron['name']})")
|
|
113
|
-
|
|
114
|
-
# List cron jobs
|
|
115
|
-
all_crons = m.cron_list()
|
|
116
|
-
print(f"Total cron jobs: {all_crons.get('total', len(all_crons.get('cron_jobs', [])))}")
|
|
117
|
-
|
|
118
|
-
# Disable it
|
|
119
|
-
m.cron_update(cron["id"], enabled=False)
|
|
120
|
-
print(f"Disabled cron job: {cron['id']}")
|
|
121
|
-
|
|
122
|
-
# Delete it
|
|
123
|
-
m.cron_delete(cron["id"])
|
|
124
|
-
print(f"Deleted cron job: {cron['id']}")
|
|
125
|
-
print()
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
def usage_example(m: Mags):
|
|
129
|
-
"""Show account usage stats."""
|
|
130
|
-
print("=== Usage Stats ===")
|
|
131
|
-
u = m.usage(window_days=30)
|
|
132
|
-
print(f"Window: {u['window_days']} days")
|
|
133
|
-
print(f"Total jobs: {u['total_jobs']}")
|
|
134
|
-
print(f"VM seconds: {u['vm_seconds']:.1f}")
|
|
135
|
-
print(f"CPU seconds: {u['cpu_seconds']:.1f}")
|
|
136
|
-
print(f"Memory (GB-seconds): {u['memory_gb_seconds']:.1f}")
|
|
137
|
-
print(f"Storage (GB-seconds): {u['storage_gb_seconds']:.1f}")
|
|
138
|
-
print(f"VM config: {u['vcpus']} vCPU, {u['memory_mb']}MB RAM, {u['disk_gb']}GB disk")
|
|
139
|
-
print()
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
def list_jobs(m: Mags):
|
|
143
|
-
"""List recent jobs."""
|
|
144
|
-
print("=== Recent Jobs ===")
|
|
145
|
-
resp = m.list_jobs(page=1, page_size=5)
|
|
146
|
-
for job in resp["jobs"]:
|
|
147
|
-
print(
|
|
148
|
-
f" {job['request_id'][:8]}.. "
|
|
149
|
-
f"{job['status']:>10} "
|
|
150
|
-
f"{job.get('name', 'unnamed')}"
|
|
151
|
-
)
|
|
152
|
-
print(f"Total: {resp['total']}")
|
|
153
|
-
print()
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
EXAMPLES = {
|
|
157
|
-
"quick": quick_run,
|
|
158
|
-
"workspace": workspace_example,
|
|
159
|
-
"url": url_access_example,
|
|
160
|
-
"cron": cron_example,
|
|
161
|
-
"usage": usage_example,
|
|
162
|
-
"list": list_jobs,
|
|
163
|
-
}
|
|
164
|
-
|
|
165
|
-
if __name__ == "__main__":
|
|
166
|
-
m = Mags() # reads MAGS_API_TOKEN from env
|
|
167
|
-
|
|
168
|
-
which = sys.argv[1] if len(sys.argv) > 1 else None
|
|
169
|
-
|
|
170
|
-
if which and which in EXAMPLES:
|
|
171
|
-
EXAMPLES[which](m)
|
|
172
|
-
elif which:
|
|
173
|
-
print(f"Unknown example: {which}")
|
|
174
|
-
print(f"Available: {', '.join(EXAMPLES)}")
|
|
175
|
-
sys.exit(1)
|
|
176
|
-
else:
|
|
177
|
-
# Run all examples
|
|
178
|
-
quick_run(m)
|
|
179
|
-
list_jobs(m)
|
|
180
|
-
usage_example(m)
|
|
181
|
-
print("(Run with 'workspace', 'url', or 'cron' arg for more examples)")
|
package/python/pyproject.toml
DELETED
|
@@ -1,39 +0,0 @@
|
|
|
1
|
-
[build-system]
|
|
2
|
-
requires = ["setuptools>=68.0", "wheel"]
|
|
3
|
-
build-backend = "setuptools.build_meta"
|
|
4
|
-
|
|
5
|
-
[project]
|
|
6
|
-
name = "magpie-mags"
|
|
7
|
-
version = "1.3.6"
|
|
8
|
-
description = "Mags SDK - Execute scripts on Magpie's instant VM infrastructure"
|
|
9
|
-
readme = "README.md"
|
|
10
|
-
license = {text = "MIT"}
|
|
11
|
-
requires-python = ">=3.8"
|
|
12
|
-
authors = [
|
|
13
|
-
{name = "Magpie Cloud"}
|
|
14
|
-
]
|
|
15
|
-
keywords = ["magpie", "mags", "vm", "microvm", "cloud", "serverless", "sandbox"]
|
|
16
|
-
classifiers = [
|
|
17
|
-
"Development Status :: 4 - Beta",
|
|
18
|
-
"Intended Audience :: Developers",
|
|
19
|
-
"License :: OSI Approved :: MIT License",
|
|
20
|
-
"Programming Language :: Python :: 3",
|
|
21
|
-
"Programming Language :: Python :: 3.8",
|
|
22
|
-
"Programming Language :: Python :: 3.9",
|
|
23
|
-
"Programming Language :: Python :: 3.10",
|
|
24
|
-
"Programming Language :: Python :: 3.11",
|
|
25
|
-
"Programming Language :: Python :: 3.12",
|
|
26
|
-
"Programming Language :: Python :: 3.13",
|
|
27
|
-
"Topic :: Software Development :: Libraries",
|
|
28
|
-
]
|
|
29
|
-
dependencies = [
|
|
30
|
-
"requests>=2.25.0",
|
|
31
|
-
]
|
|
32
|
-
|
|
33
|
-
[project.urls]
|
|
34
|
-
Homepage = "https://mags.run"
|
|
35
|
-
Repository = "https://github.com/magpiecloud/mags"
|
|
36
|
-
Issues = "https://github.com/magpiecloud/mags/issues"
|
|
37
|
-
|
|
38
|
-
[tool.setuptools.packages.find]
|
|
39
|
-
where = ["src"]
|
|
@@ -1,182 +0,0 @@
|
|
|
1
|
-
Metadata-Version: 2.4
|
|
2
|
-
Name: magpie-mags
|
|
3
|
-
Version: 1.3.5
|
|
4
|
-
Summary: Mags SDK - Execute scripts on Magpie's instant VM infrastructure
|
|
5
|
-
Author: Magpie Cloud
|
|
6
|
-
License: MIT
|
|
7
|
-
Project-URL: Homepage, https://mags.run
|
|
8
|
-
Project-URL: Repository, https://github.com/magpiecloud/mags
|
|
9
|
-
Project-URL: Issues, https://github.com/magpiecloud/mags/issues
|
|
10
|
-
Keywords: magpie,mags,vm,microvm,cloud,serverless,sandbox
|
|
11
|
-
Classifier: Development Status :: 4 - Beta
|
|
12
|
-
Classifier: Intended Audience :: Developers
|
|
13
|
-
Classifier: License :: OSI Approved :: MIT License
|
|
14
|
-
Classifier: Programming Language :: Python :: 3
|
|
15
|
-
Classifier: Programming Language :: Python :: 3.8
|
|
16
|
-
Classifier: Programming Language :: Python :: 3.9
|
|
17
|
-
Classifier: Programming Language :: Python :: 3.10
|
|
18
|
-
Classifier: Programming Language :: Python :: 3.11
|
|
19
|
-
Classifier: Programming Language :: Python :: 3.12
|
|
20
|
-
Classifier: Programming Language :: Python :: 3.13
|
|
21
|
-
Classifier: Topic :: Software Development :: Libraries
|
|
22
|
-
Requires-Python: >=3.8
|
|
23
|
-
Description-Content-Type: text/markdown
|
|
24
|
-
Requires-Dist: requests>=2.25.0
|
|
25
|
-
|
|
26
|
-
# Mags Python SDK
|
|
27
|
-
|
|
28
|
-
Execute scripts on [Magpie's](https://mags.run) instant VM infrastructure from Python.
|
|
29
|
-
|
|
30
|
-
## Install
|
|
31
|
-
|
|
32
|
-
```bash
|
|
33
|
-
pip install magpie-mags
|
|
34
|
-
```
|
|
35
|
-
|
|
36
|
-
## Quick Start
|
|
37
|
-
|
|
38
|
-
```python
|
|
39
|
-
from mags import Mags
|
|
40
|
-
|
|
41
|
-
m = Mags(api_token="your-token")
|
|
42
|
-
|
|
43
|
-
# Run a script and wait for the result
|
|
44
|
-
result = m.run_and_wait("echo 'Hello from a VM!'")
|
|
45
|
-
print(result["status"]) # "completed"
|
|
46
|
-
print(result["exit_code"]) # 0
|
|
47
|
-
for log in result["logs"]:
|
|
48
|
-
print(log["message"])
|
|
49
|
-
```
|
|
50
|
-
|
|
51
|
-
## Authentication
|
|
52
|
-
|
|
53
|
-
Pass `api_token` directly, or set one of these environment variables:
|
|
54
|
-
|
|
55
|
-
```bash
|
|
56
|
-
export MAGS_API_TOKEN="your-token"
|
|
57
|
-
# or
|
|
58
|
-
export MAGS_TOKEN="your-token"
|
|
59
|
-
```
|
|
60
|
-
|
|
61
|
-
## Usage
|
|
62
|
-
|
|
63
|
-
### Run a Script
|
|
64
|
-
|
|
65
|
-
```python
|
|
66
|
-
# Fire-and-forget
|
|
67
|
-
job = m.run("apt install -y ffmpeg && ffmpeg -version")
|
|
68
|
-
print(job["request_id"])
|
|
69
|
-
|
|
70
|
-
# Run and wait for completion
|
|
71
|
-
result = m.run_and_wait(
|
|
72
|
-
"python3 -c 'print(sum(range(100)))'",
|
|
73
|
-
timeout=30,
|
|
74
|
-
)
|
|
75
|
-
```
|
|
76
|
-
|
|
77
|
-
### Persistent Workspaces
|
|
78
|
-
|
|
79
|
-
```python
|
|
80
|
-
# First run: creates the workspace
|
|
81
|
-
m.run_and_wait(
|
|
82
|
-
"pip install pandas && echo 'setup done'",
|
|
83
|
-
workspace_id="my-project",
|
|
84
|
-
persistent=True,
|
|
85
|
-
)
|
|
86
|
-
|
|
87
|
-
# Second run: reuses the workspace (pandas is already installed)
|
|
88
|
-
m.run_and_wait(
|
|
89
|
-
"python3 -c 'import pandas; print(pandas.__version__)'",
|
|
90
|
-
workspace_id="my-project",
|
|
91
|
-
)
|
|
92
|
-
```
|
|
93
|
-
|
|
94
|
-
### Always-On VMs
|
|
95
|
-
|
|
96
|
-
```python
|
|
97
|
-
# VM that never auto-sleeps — stays running 24/7
|
|
98
|
-
job = m.run(
|
|
99
|
-
"python3 server.py",
|
|
100
|
-
workspace_id="my-api",
|
|
101
|
-
persistent=True,
|
|
102
|
-
no_sleep=True,
|
|
103
|
-
)
|
|
104
|
-
# Auto-recovers if the host goes down
|
|
105
|
-
```
|
|
106
|
-
|
|
107
|
-
### Enable URL / SSH Access
|
|
108
|
-
|
|
109
|
-
```python
|
|
110
|
-
job = m.run("python3 -m http.server 8080", persistent=True)
|
|
111
|
-
|
|
112
|
-
# HTTP access
|
|
113
|
-
access = m.enable_access(job["request_id"], port=8080)
|
|
114
|
-
print(access["url"])
|
|
115
|
-
|
|
116
|
-
# SSH access
|
|
117
|
-
ssh = m.enable_access(job["request_id"], port=22)
|
|
118
|
-
print(f"ssh root@{ssh['ssh_host']} -p {ssh['ssh_port']}")
|
|
119
|
-
```
|
|
120
|
-
|
|
121
|
-
### Upload Files
|
|
122
|
-
|
|
123
|
-
```python
|
|
124
|
-
file_ids = m.upload_files(["data.csv", "config.json"])
|
|
125
|
-
result = m.run_and_wait(
|
|
126
|
-
"ls /uploads && wc -l /uploads/data.csv",
|
|
127
|
-
file_ids=file_ids,
|
|
128
|
-
)
|
|
129
|
-
```
|
|
130
|
-
|
|
131
|
-
### Cron Jobs
|
|
132
|
-
|
|
133
|
-
```python
|
|
134
|
-
cron = m.cron_create(
|
|
135
|
-
name="nightly-backup",
|
|
136
|
-
cron_expression="0 0 * * *",
|
|
137
|
-
script="tar czf /workspace/backup.tar.gz /data",
|
|
138
|
-
workspace_id="backups",
|
|
139
|
-
)
|
|
140
|
-
|
|
141
|
-
jobs = m.cron_list()
|
|
142
|
-
m.cron_update(cron["id"], enabled=False)
|
|
143
|
-
m.cron_delete(cron["id"])
|
|
144
|
-
```
|
|
145
|
-
|
|
146
|
-
### Check Usage
|
|
147
|
-
|
|
148
|
-
```python
|
|
149
|
-
usage = m.usage(window_days=7)
|
|
150
|
-
print(f"Jobs: {usage['total_jobs']}, VM seconds: {usage['vm_seconds']:.0f}")
|
|
151
|
-
```
|
|
152
|
-
|
|
153
|
-
## API Reference
|
|
154
|
-
|
|
155
|
-
| Method | Description |
|
|
156
|
-
|--------|-------------|
|
|
157
|
-
| `run(script, **opts)` | Submit a job (`persistent`, `no_sleep`, `workspace_id`, ...) |
|
|
158
|
-
| `run_and_wait(script, **opts)` | Submit and block until done |
|
|
159
|
-
| `new(name, **opts)` | Create a VM sandbox (`persistent=True` for S3) |
|
|
160
|
-
| `find_job(name_or_id)` | Find a running/sleeping job by name or workspace |
|
|
161
|
-
| `exec(name_or_id, command)` | Run a command on an existing VM via SSH |
|
|
162
|
-
| `stop(name_or_id)` | Stop a running job |
|
|
163
|
-
| `resize(workspace, disk_gb)` | Resize a workspace's disk |
|
|
164
|
-
| `status(request_id)` | Get job status |
|
|
165
|
-
| `logs(request_id)` | Get job logs |
|
|
166
|
-
| `list_jobs(page, page_size)` | List recent jobs |
|
|
167
|
-
| `update_job(request_id, startup_command)` | Update job config |
|
|
168
|
-
| `enable_access(request_id, port)` | Enable URL or SSH access |
|
|
169
|
-
| `usage(window_days)` | Get usage summary |
|
|
170
|
-
| `upload_file(path)` | Upload a file, returns file ID |
|
|
171
|
-
| `upload_files(paths)` | Upload multiple files |
|
|
172
|
-
| `cron_create(**opts)` | Create a cron job |
|
|
173
|
-
| `cron_list()` | List cron jobs |
|
|
174
|
-
| `cron_get(id)` | Get a cron job |
|
|
175
|
-
| `cron_update(id, **updates)` | Update a cron job |
|
|
176
|
-
| `cron_delete(id)` | Delete a cron job |
|
|
177
|
-
|
|
178
|
-
## Links
|
|
179
|
-
|
|
180
|
-
- Website: [mags.run](https://mags.run)
|
|
181
|
-
- Node.js SDK: `npm install @magpiecloud/mags`
|
|
182
|
-
- CLI: `go install` or download from releases
|
|
@@ -1,9 +0,0 @@
|
|
|
1
|
-
README.md
|
|
2
|
-
pyproject.toml
|
|
3
|
-
src/magpie_mags.egg-info/PKG-INFO
|
|
4
|
-
src/magpie_mags.egg-info/SOURCES.txt
|
|
5
|
-
src/magpie_mags.egg-info/dependency_links.txt
|
|
6
|
-
src/magpie_mags.egg-info/requires.txt
|
|
7
|
-
src/magpie_mags.egg-info/top_level.txt
|
|
8
|
-
src/mags/__init__.py
|
|
9
|
-
src/mags/client.py
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
requests>=2.25.0
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
mags
|