videosdkagent-cli 0.0.1__py2.py3-none-any.whl → 0.0.5__py2.py3-none-any.whl
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.
- videosdk_cli/auth.py +95 -30
- videosdk_cli/build.py +1387 -287
- videosdk_cli/main.py +69 -36
- videosdk_cli/projects.py +36 -19
- videosdk_cli/templates.py +87 -32
- videosdk_cli/utils/analytics.py +4 -3
- videosdk_cli/utils/api_client.py +26 -24
- videosdk_cli/utils/apis/deployment_client.py +247 -86
- videosdk_cli/utils/apis/videosdk_auth_api_client.py +5 -6
- videosdk_cli/utils/auth_api_client.py +2 -2
- videosdk_cli/utils/manager/agent_manager.py +275 -107
- videosdk_cli/utils/template_helper.py +102 -28
- videosdk_cli/utils/ui/progress_runner.py +15 -7
- videosdk_cli/utils/ui/theme.py +144 -0
- videosdk_cli/utils/videosdk_yaml_helper.py +173 -23
- {videosdkagent_cli-0.0.1.dist-info → videosdkagent_cli-0.0.5.dist-info}/METADATA +2 -2
- videosdkagent_cli-0.0.5.dist-info/RECORD +28 -0
- videosdk_cli/secret_set.py +0 -82
- videosdkagent_cli-0.0.1.dist-info/RECORD +0 -28
- {videosdkagent_cli-0.0.1.dist-info → videosdkagent_cli-0.0.5.dist-info}/WHEEL +0 -0
- {videosdkagent_cli-0.0.1.dist-info → videosdkagent_cli-0.0.5.dist-info}/entry_points.txt +0 -0
videosdk_cli/build.py
CHANGED
|
@@ -1,49 +1,147 @@
|
|
|
1
|
-
from email.policy import default
|
|
2
1
|
import click
|
|
3
2
|
import sys
|
|
4
3
|
import subprocess
|
|
5
4
|
import os
|
|
6
5
|
import asyncio
|
|
7
6
|
from pathlib import Path
|
|
8
|
-
from rich.prompt import Prompt
|
|
9
|
-
from rich.console import Console
|
|
10
|
-
from InquirerPy import inquirer
|
|
11
|
-
from videosdk_cli.secret_set import secret_set
|
|
12
|
-
from videosdk_cli.utils.project_config import get_config_option
|
|
13
7
|
from docker_image.reference import Reference
|
|
8
|
+
from videosdk_cli.utils.project_config import get_config_option
|
|
14
9
|
from videosdk_cli.utils.apis.deployment_client import DeploymentClient
|
|
15
10
|
from videosdk_cli.utils.ui.progress_runner import run_with_progress
|
|
16
|
-
from videosdk_cli.utils.
|
|
17
|
-
console
|
|
11
|
+
from videosdk_cli.utils.ui.theme import (
|
|
12
|
+
console,
|
|
13
|
+
print_header,
|
|
14
|
+
print_success,
|
|
15
|
+
print_error,
|
|
16
|
+
print_warning,
|
|
17
|
+
print_info,
|
|
18
|
+
print_key_value,
|
|
19
|
+
print_divider,
|
|
20
|
+
)
|
|
21
|
+
from videosdk_cli.utils.manager.agent_manager import (
|
|
22
|
+
init_agent,
|
|
23
|
+
list_versions_manager,
|
|
24
|
+
list_sessions_manager,
|
|
25
|
+
describe_version_manager,
|
|
26
|
+
image_pull_secret_manager,
|
|
27
|
+
secret_set_manager,
|
|
28
|
+
list_secret_manager,
|
|
29
|
+
remove_secret_set,
|
|
30
|
+
describe_secret_set,
|
|
31
|
+
add_secret_set,
|
|
32
|
+
remove_secret_set_key,
|
|
33
|
+
version_logs_manager,
|
|
34
|
+
)
|
|
35
|
+
|
|
18
36
|
|
|
37
|
+
# =============================================================================
|
|
38
|
+
# MAIN AGENT GROUP
|
|
39
|
+
# =============================================================================
|
|
19
40
|
@click.group()
|
|
20
41
|
def agent_cli():
|
|
21
|
-
"""
|
|
42
|
+
"""
|
|
43
|
+
Manage VideoSDK AI Agents.
|
|
44
|
+
|
|
45
|
+
Build, deploy, and manage your AI agents with VideoSDK cloud infrastructure.
|
|
46
|
+
|
|
47
|
+
\b
|
|
48
|
+
Quick Start:
|
|
49
|
+
$ videosdk agent init --name my-agent
|
|
50
|
+
$ videosdk agent build --image myrepo/myagent:v1
|
|
51
|
+
$ videosdk agent push --image myrepo/myagent:v1
|
|
52
|
+
$ videosdk agent deploy --image myrepo/myagent:v1
|
|
53
|
+
"""
|
|
22
54
|
pass
|
|
23
55
|
|
|
56
|
+
|
|
57
|
+
# =============================================================================
|
|
58
|
+
# AGENT INIT
|
|
59
|
+
# =============================================================================
|
|
24
60
|
@agent_cli.command(name="init")
|
|
25
|
-
@click.option(
|
|
26
|
-
|
|
27
|
-
|
|
61
|
+
@click.option(
|
|
62
|
+
"--name",
|
|
63
|
+
"-n",
|
|
64
|
+
default=None,
|
|
65
|
+
help="Name for your deployment (auto-generated if not provided)",
|
|
66
|
+
)
|
|
67
|
+
@click.option(
|
|
68
|
+
"--template",
|
|
69
|
+
"-t",
|
|
70
|
+
default=None,
|
|
71
|
+
help="Template ID to use (e.g., Template01)",
|
|
72
|
+
)
|
|
73
|
+
def init(name, template):
|
|
74
|
+
"""
|
|
75
|
+
Initialize a new agent deployment.
|
|
76
|
+
|
|
77
|
+
Creates a new agent and deployment in VideoSDK cloud and generates a
|
|
78
|
+
videosdk.yaml configuration file with the agent ID and deployment ID.
|
|
79
|
+
|
|
80
|
+
\b
|
|
81
|
+
Examples:
|
|
82
|
+
$ videosdk agent init --name my-assistant --template Template01
|
|
83
|
+
$ videosdk agent init -n my-bot -t Template01
|
|
84
|
+
$ videosdk agent init # auto-generates name
|
|
85
|
+
"""
|
|
86
|
+
print_header("Initializing Deployment")
|
|
28
87
|
try:
|
|
29
|
-
asyncio.run(
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
88
|
+
asyncio.run(
|
|
89
|
+
run_with_progress(
|
|
90
|
+
init_agent(Path(os.getcwd()), name=name, template=template),
|
|
91
|
+
console=console,
|
|
92
|
+
title="Initializing Deployment",
|
|
93
|
+
duration=5.0,
|
|
94
|
+
)
|
|
95
|
+
)
|
|
96
|
+
print_success("Deployment initialized successfully")
|
|
97
|
+
print_info("Next step: Build your agent Docker image")
|
|
98
|
+
console.print(
|
|
99
|
+
" [bold]videosdk agent build --image <your-docker-username>/<image-name>:<tag>[/bold]"
|
|
100
|
+
)
|
|
36
101
|
except Exception as e:
|
|
37
|
-
|
|
102
|
+
print_error(f"Error: {e}")
|
|
38
103
|
sys.exit(1)
|
|
39
104
|
|
|
40
105
|
|
|
106
|
+
# =============================================================================
|
|
107
|
+
# AGENT BUILD
|
|
108
|
+
# =============================================================================
|
|
41
109
|
@agent_cli.command(name="build")
|
|
42
|
-
@click.option(
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
110
|
+
@click.option(
|
|
111
|
+
"--image",
|
|
112
|
+
"-i",
|
|
113
|
+
default=None,
|
|
114
|
+
help="Image name with optional tag (e.g., myrepo/myagent:v1)",
|
|
115
|
+
)
|
|
116
|
+
@click.option(
|
|
117
|
+
"--file",
|
|
118
|
+
"-f",
|
|
119
|
+
"dockerfile",
|
|
120
|
+
default=None,
|
|
121
|
+
help="Path to Dockerfile (default: ./Dockerfile)",
|
|
122
|
+
)
|
|
123
|
+
@click.option(
|
|
124
|
+
"--enable-logs",
|
|
125
|
+
is_flag=True,
|
|
126
|
+
default=False,
|
|
127
|
+
help="Upload build logs to VideoSDK cloud",
|
|
128
|
+
)
|
|
129
|
+
def build(image, dockerfile, enable_logs):
|
|
130
|
+
"""
|
|
131
|
+
Build a Docker image for your agent.
|
|
132
|
+
|
|
133
|
+
Builds a Docker image using the specified Dockerfile. The image tag
|
|
134
|
+
can be provided via --image flag or read from videosdk.yaml.
|
|
135
|
+
|
|
136
|
+
\b
|
|
137
|
+
Examples:
|
|
138
|
+
$ videosdk agent build --image myrepo/myagent:v1
|
|
139
|
+
$ videosdk agent build --image myrepo/myagent:v1 --file Dockerfile.prod
|
|
140
|
+
$ videosdk agent build --enable-logs # upload build logs to cloud
|
|
141
|
+
$ videosdk agent build # uses image from videosdk.yaml
|
|
142
|
+
"""
|
|
143
|
+
platform = "linux/arm64"
|
|
144
|
+
|
|
47
145
|
# Determine Dockerfile path
|
|
48
146
|
if dockerfile:
|
|
49
147
|
dockerfile_path = Path(os.getcwd()) / dockerfile
|
|
@@ -52,379 +150,1381 @@ def build(tag, dockerfile):
|
|
|
52
150
|
dockerfile = "Dockerfile"
|
|
53
151
|
|
|
54
152
|
if not dockerfile_path.exists():
|
|
55
|
-
|
|
153
|
+
print_error(f"Dockerfile not found at {dockerfile_path}")
|
|
56
154
|
sys.exit(1)
|
|
57
155
|
|
|
58
|
-
# Resolve tag
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
[
|
|
62
|
-
required=
|
|
63
|
-
fail_message="--tag not provided and 'agent.image' not found in videosdk.yaml"
|
|
156
|
+
# Resolve image tag: CLI > build.image > agent.image (legacy)
|
|
157
|
+
image = get_config_option(
|
|
158
|
+
image,
|
|
159
|
+
["build", "image"],
|
|
160
|
+
required=False,
|
|
64
161
|
)
|
|
65
|
-
|
|
162
|
+
if image is None:
|
|
163
|
+
image = get_config_option(
|
|
164
|
+
None,
|
|
165
|
+
["agent", "image"],
|
|
166
|
+
required=True,
|
|
167
|
+
fail_message="--image not provided and 'build.image' or 'agent.image' not found in videosdk.yaml",
|
|
168
|
+
)
|
|
169
|
+
image = image.lower()
|
|
170
|
+
|
|
171
|
+
# If logs enabled, get deployment_id and presigned URL
|
|
172
|
+
presigned_url = None
|
|
173
|
+
build_id = None
|
|
174
|
+
deployment_id = None
|
|
175
|
+
|
|
176
|
+
if enable_logs:
|
|
177
|
+
deployment_id = get_config_option(
|
|
178
|
+
None,
|
|
179
|
+
["deploy", "id"],
|
|
180
|
+
required=True,
|
|
181
|
+
fail_message="--enable-logs requires 'deploy.id' in videosdk.yaml. Run 'videosdk agent init' first.",
|
|
182
|
+
)
|
|
183
|
+
|
|
184
|
+
# Extract tag from image (e.g., "myrepo/myagent:v1" -> "v1")
|
|
185
|
+
if ":" in image:
|
|
186
|
+
image_tag = image.split(":")[-1]
|
|
187
|
+
else:
|
|
188
|
+
image_tag = "latest"
|
|
189
|
+
|
|
190
|
+
print_info("Getting presigned URL for build logs...")
|
|
191
|
+
try:
|
|
192
|
+
client = DeploymentClient()
|
|
193
|
+
response = asyncio.run(
|
|
194
|
+
client.get_build_log_presigned_url(
|
|
195
|
+
deployment_id=deployment_id,
|
|
196
|
+
tag=image_tag,
|
|
197
|
+
)
|
|
198
|
+
)
|
|
199
|
+
presigned_url = response.get("presignedUrl")
|
|
200
|
+
build_id = response.get("buildId")
|
|
201
|
+
print_success(f"Build ID: {build_id}")
|
|
202
|
+
except Exception as e:
|
|
203
|
+
print_warning(f"Failed to get presigned URL: {e}")
|
|
204
|
+
print_warning("Build will continue without log upload")
|
|
205
|
+
enable_logs = False
|
|
66
206
|
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
207
|
+
print_header("Building Docker Image")
|
|
208
|
+
print_key_value("Platform", platform)
|
|
209
|
+
print_key_value("Image", image)
|
|
210
|
+
print_key_value("Dockerfile", str(dockerfile_path))
|
|
211
|
+
if enable_logs:
|
|
212
|
+
print_key_value("Log Upload", "Enabled")
|
|
213
|
+
print_key_value("Build ID", build_id)
|
|
214
|
+
print_divider()
|
|
71
215
|
|
|
72
216
|
cmd = [
|
|
73
|
-
"docker",
|
|
74
|
-
"
|
|
75
|
-
"
|
|
76
|
-
|
|
77
|
-
"
|
|
217
|
+
"docker",
|
|
218
|
+
"build",
|
|
219
|
+
"--platform",
|
|
220
|
+
platform,
|
|
221
|
+
"-t",
|
|
222
|
+
image,
|
|
223
|
+
"-f",
|
|
224
|
+
str(dockerfile),
|
|
225
|
+
".",
|
|
78
226
|
]
|
|
79
227
|
|
|
228
|
+
build_success = False
|
|
229
|
+
build_output = ""
|
|
230
|
+
|
|
80
231
|
try:
|
|
81
|
-
|
|
82
|
-
|
|
232
|
+
if enable_logs:
|
|
233
|
+
# Run with captured output (still shows to user via PIPE + real-time read)
|
|
234
|
+
process = subprocess.Popen(
|
|
235
|
+
cmd,
|
|
236
|
+
stdout=subprocess.PIPE,
|
|
237
|
+
stderr=subprocess.STDOUT,
|
|
238
|
+
text=True,
|
|
239
|
+
bufsize=1,
|
|
240
|
+
)
|
|
241
|
+
|
|
242
|
+
output_lines = []
|
|
243
|
+
for line in process.stdout:
|
|
244
|
+
console.print(line, end="")
|
|
245
|
+
output_lines.append(line)
|
|
246
|
+
|
|
247
|
+
process.wait()
|
|
248
|
+
build_output = "".join(output_lines)
|
|
249
|
+
|
|
250
|
+
if process.returncode != 0:
|
|
251
|
+
raise subprocess.CalledProcessError(process.returncode, cmd)
|
|
252
|
+
else:
|
|
253
|
+
# Run without capturing (direct output to terminal)
|
|
254
|
+
subprocess.run(cmd, check=True)
|
|
255
|
+
|
|
256
|
+
build_success = True
|
|
257
|
+
console.print()
|
|
258
|
+
print_success(f"Successfully built image: {image}")
|
|
259
|
+
print_info(f"Next step: Push your image to registry")
|
|
260
|
+
console.print(f" [bold]videosdk agent push --image {image}[/bold]")
|
|
261
|
+
|
|
83
262
|
except subprocess.CalledProcessError as e:
|
|
84
|
-
|
|
85
|
-
|
|
263
|
+
print_error("Failed to build image")
|
|
264
|
+
build_success = False
|
|
265
|
+
if not enable_logs:
|
|
266
|
+
sys.exit(e.returncode)
|
|
86
267
|
except FileNotFoundError:
|
|
87
|
-
|
|
268
|
+
print_error(
|
|
269
|
+
"'docker' command not found. Please ensure Docker is installed and in your PATH."
|
|
270
|
+
)
|
|
88
271
|
sys.exit(1)
|
|
89
272
|
|
|
273
|
+
# Handle build logs and yaml updates
|
|
274
|
+
from videosdk_cli.utils.videosdk_yaml_helper import (
|
|
275
|
+
update_agent_config,
|
|
276
|
+
BuildConfig,
|
|
277
|
+
BuildLogsConfig,
|
|
278
|
+
)
|
|
279
|
+
import yaml
|
|
280
|
+
|
|
281
|
+
if enable_logs and presigned_url and build_output:
|
|
282
|
+
# Upload logs if enabled
|
|
283
|
+
print_info("Uploading build logs...")
|
|
284
|
+
try:
|
|
285
|
+
import aiohttp
|
|
90
286
|
|
|
287
|
+
async def upload_logs():
|
|
288
|
+
async with aiohttp.ClientSession() as session:
|
|
289
|
+
async with session.put(
|
|
290
|
+
presigned_url,
|
|
291
|
+
data=build_output.encode("utf-8"),
|
|
292
|
+
headers={"Content-Type": "text/plain"},
|
|
293
|
+
) as resp:
|
|
294
|
+
if resp.status not in (200, 201, 204):
|
|
295
|
+
raise Exception(f"Upload failed with status {resp.status}")
|
|
296
|
+
|
|
297
|
+
asyncio.run(upload_logs())
|
|
298
|
+
print_success("Build logs uploaded successfully")
|
|
299
|
+
|
|
300
|
+
# Save new build_id to videosdk.yaml (replaces any old one)
|
|
301
|
+
build_config = BuildConfig(logs=BuildLogsConfig(id=build_id, enabled=True))
|
|
302
|
+
update_agent_config(
|
|
303
|
+
app_dir=Path(os.getcwd()),
|
|
304
|
+
build_config=build_config,
|
|
305
|
+
)
|
|
306
|
+
print_success(f"Build ID saved to videosdk.yaml: {build_id}")
|
|
307
|
+
|
|
308
|
+
except Exception as e:
|
|
309
|
+
print_warning(f"Failed to upload build logs: {e}")
|
|
310
|
+
elif not enable_logs:
|
|
311
|
+
# Clear build logs from yaml if logs are not enabled
|
|
312
|
+
# This ensures old build IDs don't get used for new builds
|
|
313
|
+
try:
|
|
314
|
+
config_file = Path(os.getcwd()) / "videosdk.yaml"
|
|
315
|
+
if config_file.exists():
|
|
316
|
+
with open(config_file, "r") as f:
|
|
317
|
+
config_data = yaml.safe_load(f) or {}
|
|
318
|
+
|
|
319
|
+
# Remove build.logs section if it exists
|
|
320
|
+
if "build" in config_data and isinstance(config_data["build"], dict):
|
|
321
|
+
if "logs" in config_data["build"]:
|
|
322
|
+
del config_data["build"]["logs"]
|
|
323
|
+
# If build section is now empty, remove it
|
|
324
|
+
if not config_data["build"]:
|
|
325
|
+
del config_data["build"]
|
|
326
|
+
|
|
327
|
+
# Write back
|
|
328
|
+
with open(config_file, "w") as f:
|
|
329
|
+
yaml.dump(config_data, f, default_flow_style=False, sort_keys=False)
|
|
330
|
+
except Exception:
|
|
331
|
+
# Silently fail if yaml doesn't exist or can't be updated
|
|
332
|
+
pass
|
|
333
|
+
|
|
334
|
+
# Exit with error if build failed
|
|
335
|
+
if not build_success:
|
|
336
|
+
sys.exit(1)
|
|
337
|
+
|
|
338
|
+
|
|
339
|
+
# =============================================================================
|
|
340
|
+
# AGENT PUSH
|
|
341
|
+
# =============================================================================
|
|
91
342
|
@agent_cli.command(name="push")
|
|
92
|
-
@click.option(
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
@click.option(
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
343
|
+
@click.option(
|
|
344
|
+
"--image", "-i", default=None, help="Image name with tag (e.g., myrepo/myagent:v1)"
|
|
345
|
+
)
|
|
346
|
+
@click.option(
|
|
347
|
+
"--server", "-s", default=None, help="Registry server URL (default: docker.io)"
|
|
348
|
+
)
|
|
349
|
+
@click.option(
|
|
350
|
+
"--username", "-u", default=None, help="Registry username for authentication"
|
|
351
|
+
)
|
|
352
|
+
@click.option(
|
|
353
|
+
"--password", "-p", default=None, help="Registry password for authentication"
|
|
354
|
+
)
|
|
355
|
+
def push(image, server, username, password):
|
|
356
|
+
"""
|
|
357
|
+
Push a Docker image to a container registry.
|
|
358
|
+
|
|
359
|
+
Pushes the built Docker image to Docker Hub or a private registry.
|
|
360
|
+
Optionally authenticate with username/password.
|
|
361
|
+
|
|
362
|
+
\b
|
|
363
|
+
Examples:
|
|
364
|
+
$ videosdk agent push --image myrepo/myagent:v1
|
|
365
|
+
$ videosdk agent push --image myrepo/myagent:v1 --server ghcr.io -u user -p token
|
|
366
|
+
$ videosdk agent push # uses image from videosdk.yaml
|
|
367
|
+
"""
|
|
368
|
+
|
|
369
|
+
# Resolve image tag: CLI > build.image > agent.image (legacy)
|
|
370
|
+
image = get_config_option(
|
|
371
|
+
image,
|
|
372
|
+
["build", "image"],
|
|
373
|
+
required=False,
|
|
105
374
|
)
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
375
|
+
if image is None:
|
|
376
|
+
image = get_config_option(
|
|
377
|
+
None,
|
|
378
|
+
["agent", "image"],
|
|
379
|
+
required=True,
|
|
380
|
+
fail_message="--image not provided and 'build.image' or 'agent.image' not found in videosdk.yaml",
|
|
381
|
+
)
|
|
382
|
+
image = image.lower()
|
|
383
|
+
ref = Reference.parse_normalized_named(image)
|
|
384
|
+
hostname, name = ref.split_hostname()
|
|
385
|
+
registry = server or hostname
|
|
110
386
|
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
387
|
+
print_header("Pushing Docker Image")
|
|
388
|
+
print_key_value("Image", image)
|
|
389
|
+
print_key_value("Registry", registry)
|
|
390
|
+
print_divider()
|
|
114
391
|
|
|
115
|
-
#
|
|
392
|
+
# Docker Login (if credentials provided)
|
|
116
393
|
if username and password:
|
|
117
394
|
login_cmd = ["docker", "login", "-u", username, "-p", password]
|
|
118
395
|
if registry != "docker.io":
|
|
119
396
|
login_cmd.append(registry)
|
|
120
|
-
|
|
121
|
-
|
|
397
|
+
|
|
398
|
+
print_info(f"Logging into {registry}...")
|
|
122
399
|
try:
|
|
123
400
|
subprocess.run(login_cmd, check=True)
|
|
124
|
-
|
|
401
|
+
print_success("Login successful")
|
|
125
402
|
except subprocess.CalledProcessError:
|
|
126
|
-
|
|
403
|
+
print_error("Login failed")
|
|
127
404
|
sys.exit(1)
|
|
128
405
|
except FileNotFoundError:
|
|
129
|
-
|
|
406
|
+
print_error("'docker' command not found")
|
|
130
407
|
sys.exit(1)
|
|
131
408
|
|
|
132
|
-
#
|
|
133
|
-
push_cmd = ["docker", "push",
|
|
409
|
+
# Docker Push
|
|
410
|
+
push_cmd = ["docker", "push", image]
|
|
134
411
|
try:
|
|
135
412
|
subprocess.run(push_cmd, check=True)
|
|
136
|
-
console.print(
|
|
413
|
+
console.print()
|
|
414
|
+
print_success(f"Successfully pushed image: {image}")
|
|
415
|
+
print_info(f"Next step: Deploy your agent")
|
|
416
|
+
console.print(f" [bold]videosdk agent deploy --image {image}[/bold]")
|
|
137
417
|
except subprocess.CalledProcessError:
|
|
138
|
-
|
|
418
|
+
print_error("Failed to push image")
|
|
139
419
|
sys.exit(1)
|
|
140
420
|
except FileNotFoundError:
|
|
141
|
-
|
|
421
|
+
print_error("'docker' command not found")
|
|
142
422
|
sys.exit(1)
|
|
143
423
|
|
|
144
424
|
|
|
425
|
+
# =============================================================================
|
|
426
|
+
# AGENT DEPLOY (creates a new version)
|
|
427
|
+
# =============================================================================
|
|
145
428
|
@agent_cli.command(name="deploy")
|
|
146
|
-
@click.
|
|
429
|
+
@click.argument("name", required=False, default=None)
|
|
147
430
|
@click.option(
|
|
148
|
-
"--
|
|
149
|
-
|
|
431
|
+
"--image", "-i", default=None, help="Docker image URL (e.g., myrepo/myagent:v1)"
|
|
432
|
+
)
|
|
433
|
+
@click.option(
|
|
434
|
+
"--version-tag",
|
|
435
|
+
default=None,
|
|
436
|
+
help="Version tag (e.g., main/0.0.2)",
|
|
437
|
+
)
|
|
438
|
+
@click.option(
|
|
439
|
+
"--min-replica",
|
|
150
440
|
type=click.IntRange(min=0),
|
|
151
|
-
help="Minimum replicas (
|
|
441
|
+
help="Minimum number of replicas (default: 1)",
|
|
442
|
+
)
|
|
443
|
+
@click.option(
|
|
444
|
+
"--max-replica",
|
|
445
|
+
type=click.IntRange(min=0, max=10),
|
|
446
|
+
help="Maximum number of replicas (default: 5)",
|
|
447
|
+
)
|
|
448
|
+
@click.option(
|
|
449
|
+
"--profile",
|
|
450
|
+
default="cpu-small",
|
|
451
|
+
help="Compute profile: cpu-small, cpu-medium, cpu-large (default: cpu-small)",
|
|
452
|
+
)
|
|
453
|
+
@click.option(
|
|
454
|
+
"--agent-id",
|
|
455
|
+
default=None,
|
|
456
|
+
help="Agent ID (reads from videosdk.yaml if not provided)",
|
|
457
|
+
)
|
|
458
|
+
@click.option(
|
|
459
|
+
"--deployment-id",
|
|
460
|
+
default=None,
|
|
461
|
+
help="Deployment ID (reads from videosdk.yaml if not provided)",
|
|
462
|
+
)
|
|
463
|
+
@click.option(
|
|
464
|
+
"--env-secret", default=None, help="ID of the environment secret set to use"
|
|
465
|
+
)
|
|
466
|
+
@click.option(
|
|
467
|
+
"--image-pull-secret",
|
|
468
|
+
default=None,
|
|
469
|
+
help="Name of the image pull secret for private registries",
|
|
470
|
+
)
|
|
471
|
+
@click.option(
|
|
472
|
+
"--region", default=None, help="Deployment region (e.g., us-east, eu-west)"
|
|
152
473
|
)
|
|
153
474
|
@click.option(
|
|
154
|
-
"--
|
|
155
|
-
default=
|
|
156
|
-
|
|
157
|
-
help="Maximum replicas (0–50)",
|
|
475
|
+
"--build-id",
|
|
476
|
+
default=None,
|
|
477
|
+
help="Build ID from build logs (reads from videosdk.yaml if logs were enabled)",
|
|
158
478
|
)
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
479
|
+
def deploy(
|
|
480
|
+
name,
|
|
481
|
+
image,
|
|
482
|
+
version_tag,
|
|
483
|
+
min_replica,
|
|
484
|
+
max_replica,
|
|
485
|
+
profile,
|
|
486
|
+
agent_id,
|
|
487
|
+
deployment_id,
|
|
488
|
+
env_secret,
|
|
489
|
+
image_pull_secret,
|
|
490
|
+
region,
|
|
491
|
+
build_id,
|
|
492
|
+
):
|
|
493
|
+
"""
|
|
494
|
+
Deploy a new version of your agent to VideoSDK cloud.
|
|
165
495
|
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
496
|
+
Creates a new version with the specified configuration. The agent
|
|
497
|
+
will be scaled between min-replica and max-replica based on demand.
|
|
498
|
+
|
|
499
|
+
\b
|
|
500
|
+
Examples:
|
|
501
|
+
$ videosdk agent deploy --image myrepo/myagent:v1
|
|
502
|
+
$ videosdk agent deploy my-version --image myrepo/myagent:v1 --version-tag main/0.0.1
|
|
503
|
+
$ videosdk agent deploy --image myrepo/myagent:v1 --env-secret my-secrets --profile cpu-medium
|
|
504
|
+
$ videosdk agent deploy --build-id b_abc123 # link to build logs
|
|
505
|
+
"""
|
|
170
506
|
|
|
171
|
-
# Resolve
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
[
|
|
175
|
-
required=
|
|
176
|
-
fail_message="--tag not provided and 'agent.image' not found in videosdk.yaml"
|
|
507
|
+
# Resolve image: CLI > build.image > agent.image (legacy)
|
|
508
|
+
image = get_config_option(
|
|
509
|
+
image,
|
|
510
|
+
["build", "image"],
|
|
511
|
+
required=False,
|
|
177
512
|
)
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
513
|
+
if image is None:
|
|
514
|
+
image = get_config_option(
|
|
515
|
+
None,
|
|
516
|
+
["agent", "image"],
|
|
517
|
+
required=True,
|
|
518
|
+
fail_message="--image not provided and 'build.image' or 'agent.image' not found in videosdk.yaml",
|
|
519
|
+
)
|
|
520
|
+
ref = Reference.parse_normalized_named(image)
|
|
521
|
+
hostname, img_name = ref.split_hostname()
|
|
522
|
+
image_url = image
|
|
182
523
|
|
|
524
|
+
# Resolve agent_id
|
|
183
525
|
agent_id = get_config_option(
|
|
184
526
|
agent_id,
|
|
185
|
-
[
|
|
527
|
+
["agent", "id"],
|
|
186
528
|
required=True,
|
|
187
|
-
fail_message="--agent-id not provided and 'agent.id' not found in videosdk.yaml"
|
|
529
|
+
fail_message="--agent-id not provided and 'agent.id' not found in videosdk.yaml",
|
|
530
|
+
)
|
|
531
|
+
|
|
532
|
+
# Resolve deployment_id
|
|
533
|
+
deployment_id = get_config_option(
|
|
534
|
+
deployment_id,
|
|
535
|
+
["deploy", "id"],
|
|
536
|
+
required=True,
|
|
537
|
+
fail_message="--deployment-id not provided and 'deploy.id' not found in videosdk.yaml",
|
|
538
|
+
)
|
|
539
|
+
|
|
540
|
+
# Resolve build_id: CLI > build.logs.id (if logs were enabled)
|
|
541
|
+
build_id = get_config_option(
|
|
542
|
+
build_id,
|
|
543
|
+
["build", "logs", "id"],
|
|
544
|
+
required=False,
|
|
188
545
|
)
|
|
189
|
-
|
|
190
|
-
console.print(f"[bold blue]Deploying Agent...[/bold blue]")
|
|
191
|
-
console.print(f"Agent ID: [green]{agent_id}[/green]")
|
|
192
|
-
console.print(f"Image: [green]{image_url}[/green]")
|
|
193
|
-
console.print(f"Replicas: [green]{minreplica}-{maxreplica}[/green]")
|
|
194
|
-
console.print(f"Profile: [green]{profile}[/green]")
|
|
195
546
|
|
|
547
|
+
agent_name = get_config_option(
|
|
548
|
+
None,
|
|
549
|
+
["agent", "name"],
|
|
550
|
+
required=False,
|
|
551
|
+
)
|
|
552
|
+
|
|
553
|
+
name = get_config_option(
|
|
554
|
+
name,
|
|
555
|
+
["deploy", "name"],
|
|
556
|
+
required=False,
|
|
557
|
+
default=f"{agent_name}'s version",
|
|
558
|
+
)
|
|
559
|
+
|
|
560
|
+
min_replica = get_config_option(
|
|
561
|
+
min_replica, ["deploy", "replicas", "min"], required=False, default=1
|
|
562
|
+
)
|
|
563
|
+
max_replica = get_config_option(
|
|
564
|
+
max_replica, ["deploy", "replicas", "max"], required=False, default=3
|
|
565
|
+
)
|
|
566
|
+
if max_replica < min_replica:
|
|
567
|
+
print_error(
|
|
568
|
+
f"Max replicas({max_replica}) cannot be less than min replicas({min_replica})"
|
|
569
|
+
)
|
|
570
|
+
sys.exit(1)
|
|
571
|
+
|
|
572
|
+
profile = get_config_option(profile, ["deploy", "profile"], required=False)
|
|
573
|
+
|
|
574
|
+
region = get_config_option(region, ["deploy", "region"], required=False)
|
|
575
|
+
|
|
576
|
+
env_secret = get_config_option(env_secret, ["secrets", "env"], required=False)
|
|
577
|
+
|
|
578
|
+
image_pull_secret = get_config_option(
|
|
579
|
+
image_pull_secret, ["secrets", "image-pull"], required=False
|
|
580
|
+
)
|
|
581
|
+
print_header("Creating Version")
|
|
582
|
+
if name:
|
|
583
|
+
print_key_value("Version Name", name)
|
|
584
|
+
if version_tag:
|
|
585
|
+
print_key_value("Version Tag", version_tag)
|
|
586
|
+
print_key_value("Agent ID", agent_id)
|
|
587
|
+
print_key_value("Deployment ID", deployment_id)
|
|
588
|
+
print_key_value("Image", image_url)
|
|
589
|
+
if min_replica:
|
|
590
|
+
print_key_value("Min Replicas", min_replica)
|
|
591
|
+
if max_replica:
|
|
592
|
+
print_key_value("Max Replicas", max_replica)
|
|
593
|
+
if profile:
|
|
594
|
+
print_key_value("Profile", profile)
|
|
595
|
+
if region:
|
|
596
|
+
print_key_value("Region", region)
|
|
597
|
+
if env_secret:
|
|
598
|
+
print_key_value("Env Secret", env_secret)
|
|
599
|
+
if image_pull_secret:
|
|
600
|
+
print_key_value("Image Pull Secret", image_pull_secret)
|
|
601
|
+
if build_id:
|
|
602
|
+
print_key_value("Build ID", build_id)
|
|
603
|
+
print_divider()
|
|
196
604
|
client = DeploymentClient()
|
|
197
605
|
try:
|
|
198
|
-
asyncio.run(
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
606
|
+
response = asyncio.run(
|
|
607
|
+
run_with_progress(
|
|
608
|
+
client.create_version(
|
|
609
|
+
name=name,
|
|
610
|
+
agent_id=agent_id,
|
|
611
|
+
deployment_id=deployment_id,
|
|
612
|
+
version_tag=version_tag,
|
|
613
|
+
image_url=image_url,
|
|
614
|
+
min_replica=min_replica,
|
|
615
|
+
max_replica=max_replica,
|
|
616
|
+
profile=profile,
|
|
617
|
+
image_cr=hostname,
|
|
618
|
+
image_pull_secret=image_pull_secret,
|
|
619
|
+
env_secret=env_secret,
|
|
620
|
+
region=region,
|
|
621
|
+
build_id=build_id,
|
|
622
|
+
),
|
|
623
|
+
console=console,
|
|
624
|
+
title="Creating Version",
|
|
625
|
+
duration=5.0,
|
|
626
|
+
)
|
|
627
|
+
)
|
|
628
|
+
version_id = response.get("id") if response else None
|
|
629
|
+
print_success(f"Version created successfully for agent: {agent_id} and versionId: {version_id}")
|
|
630
|
+
if version_id:
|
|
631
|
+
print_key_value("Version ID", version_id)
|
|
632
|
+
print_info("Next step: Check version status")
|
|
633
|
+
console.print(
|
|
634
|
+
f" [bold]videosdk agent version status -v {version_id}[/bold]"
|
|
635
|
+
)
|
|
214
636
|
except KeyboardInterrupt:
|
|
215
|
-
|
|
637
|
+
print_warning("Version creation cancelled by user")
|
|
216
638
|
raise click.Abort()
|
|
217
639
|
except Exception as e:
|
|
218
|
-
|
|
640
|
+
print_error(f"Version creation failed: {e}")
|
|
219
641
|
|
|
220
642
|
|
|
221
|
-
@agent_cli.command(name="
|
|
222
|
-
@click.option("--deployment-id","-d",required=True,help="deployment id you want to update")
|
|
643
|
+
@agent_cli.command(name="logs")
|
|
223
644
|
@click.option(
|
|
224
|
-
"--
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
)
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
)
|
|
233
|
-
|
|
234
|
-
@click.option(
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
645
|
+
"--version-id",
|
|
646
|
+
"-v",
|
|
647
|
+
default=None,
|
|
648
|
+
help="Version ID (uses latest if not provided)",
|
|
649
|
+
)
|
|
650
|
+
@click.option(
|
|
651
|
+
"--agent-id",
|
|
652
|
+
default=None,
|
|
653
|
+
help="Agent ID (reads from videosdk.yaml if not provided)",
|
|
654
|
+
)
|
|
655
|
+
@click.option(
|
|
656
|
+
"--limit",
|
|
657
|
+
"-n",
|
|
658
|
+
default=50,
|
|
659
|
+
type=click.IntRange(min=1, max=1000),
|
|
660
|
+
help="Number of log entries to show (default: 50)",
|
|
661
|
+
)
|
|
662
|
+
def logs(version_id, agent_id, limit):
|
|
663
|
+
"""
|
|
664
|
+
View console logs for a version.
|
|
665
|
+
|
|
666
|
+
Shows the latest console output from your agent version.
|
|
667
|
+
Useful for debugging and monitoring agent behavior.
|
|
668
|
+
|
|
669
|
+
\b
|
|
670
|
+
Examples:
|
|
671
|
+
$ videosdk agent logs
|
|
672
|
+
$ videosdk agent logs --agent-id abc123 --version-id ver123
|
|
673
|
+
$ videosdk agent logs --limit 100
|
|
674
|
+
"""
|
|
675
|
+
print_header("Agent Deployment Logs")
|
|
246
676
|
|
|
247
677
|
agent_id = get_config_option(
|
|
248
678
|
agent_id,
|
|
249
|
-
[
|
|
679
|
+
["agent", "id"],
|
|
250
680
|
required=True,
|
|
251
|
-
fail_message="--agent-id not provided and 'agent.id' not found in videosdk.yaml"
|
|
681
|
+
fail_message="--agent-id not provided and 'agent.id' not found in videosdk.yaml",
|
|
252
682
|
)
|
|
253
|
-
|
|
254
|
-
|
|
683
|
+
|
|
684
|
+
deployment_id = get_config_option(
|
|
685
|
+
None,
|
|
686
|
+
["deploy", "id"],
|
|
687
|
+
required=True,
|
|
688
|
+
fail_message="'deploy.id' not found in videosdk.yaml",
|
|
689
|
+
)
|
|
690
|
+
|
|
691
|
+
print_key_value("Agent ID", agent_id)
|
|
692
|
+
if version_id:
|
|
693
|
+
print_key_value("Version ID", version_id)
|
|
694
|
+
print_key_value("Limit", str(limit))
|
|
695
|
+
print_divider()
|
|
696
|
+
|
|
255
697
|
try:
|
|
256
|
-
asyncio.run(
|
|
257
|
-
|
|
258
|
-
deployment_id=deployment_id,
|
|
698
|
+
asyncio.run(
|
|
699
|
+
version_logs_manager(
|
|
259
700
|
agent_id=agent_id,
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
max_replica=maxreplica,
|
|
266
|
-
profile=profile
|
|
267
|
-
),
|
|
268
|
-
console=console,
|
|
269
|
-
title="Updating Deployment",
|
|
270
|
-
duration=5.0,
|
|
271
|
-
))
|
|
272
|
-
console.print(f"[bold green]Deployment updated successfully[/bold green]")
|
|
273
|
-
except KeyboardInterrupt:
|
|
274
|
-
console.print("\n[yellow]Deployment update cancelled by user.[/yellow]")
|
|
275
|
-
raise click.Abort()
|
|
701
|
+
deployment_id=deployment_id,
|
|
702
|
+
version_id=version_id,
|
|
703
|
+
limit=limit,
|
|
704
|
+
)
|
|
705
|
+
)
|
|
276
706
|
except Exception as e:
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
#
|
|
281
|
-
#
|
|
282
|
-
|
|
283
|
-
@click.
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
707
|
+
print_error(str(e))
|
|
708
|
+
|
|
709
|
+
|
|
710
|
+
# =============================================================================
|
|
711
|
+
# VERSION SUBGROUP
|
|
712
|
+
# =============================================================================
|
|
713
|
+
@click.group()
|
|
714
|
+
def version_cli():
|
|
715
|
+
"""
|
|
716
|
+
Manage agent versions.
|
|
717
|
+
|
|
718
|
+
View, update, and control the lifecycle of your agent versions.
|
|
719
|
+
|
|
720
|
+
\b
|
|
721
|
+
Commands:
|
|
722
|
+
list List all versions for an agent deployment
|
|
723
|
+
update Update version configuration
|
|
724
|
+
activate Activate a version
|
|
725
|
+
deactivate Deactivate a version
|
|
726
|
+
status Get version status
|
|
727
|
+
describe Get detailed version info
|
|
728
|
+
"""
|
|
729
|
+
pass
|
|
730
|
+
|
|
731
|
+
|
|
732
|
+
@version_cli.command(name="list")
|
|
733
|
+
@click.option(
|
|
734
|
+
"--agent-id",
|
|
735
|
+
default=None,
|
|
736
|
+
help="Agent ID (reads from videosdk.yaml if not provided)",
|
|
737
|
+
)
|
|
738
|
+
@click.option(
|
|
739
|
+
"--deployment-id",
|
|
740
|
+
default=None,
|
|
741
|
+
help="Deployment ID (reads from videosdk.yaml if not provided)",
|
|
742
|
+
)
|
|
743
|
+
@click.option(
|
|
744
|
+
"--page",
|
|
745
|
+
default=1,
|
|
746
|
+
type=click.IntRange(min=1),
|
|
747
|
+
help="Page number (default: 1)",
|
|
748
|
+
)
|
|
749
|
+
@click.option(
|
|
750
|
+
"--per-page",
|
|
751
|
+
default=10,
|
|
752
|
+
type=click.IntRange(min=1, max=100),
|
|
753
|
+
help="Items per page (default: 10)",
|
|
754
|
+
)
|
|
755
|
+
@click.option(
|
|
756
|
+
"--sort",
|
|
757
|
+
default="-1",
|
|
758
|
+
type=click.Choice(["1", "-1"]),
|
|
759
|
+
help="Sort order: 1 (oldest first) or -1 (newest first, default)",
|
|
760
|
+
)
|
|
761
|
+
def version_list(agent_id, deployment_id, page, per_page, sort):
|
|
762
|
+
"""
|
|
763
|
+
List all versions for an agent.
|
|
764
|
+
|
|
765
|
+
Shows a table of all versions with their status, region, and profile.
|
|
766
|
+
|
|
767
|
+
\b
|
|
768
|
+
Examples:
|
|
769
|
+
$ videosdk agent version list
|
|
770
|
+
$ videosdk agent version list --agent-id abc123
|
|
771
|
+
$ videosdk agent version list --page 2 --per-page 20
|
|
772
|
+
$ videosdk agent version list --sort 1 # oldest first
|
|
773
|
+
"""
|
|
774
|
+
print_header("Listing Versions")
|
|
289
775
|
agent_id = get_config_option(
|
|
290
776
|
agent_id,
|
|
291
|
-
[
|
|
777
|
+
["agent", "id"],
|
|
292
778
|
required=True,
|
|
293
|
-
fail_message="--agent-id not provided and 'agent.id' not found in videosdk.yaml"
|
|
779
|
+
fail_message="--agent-id not provided and 'agent.id' not found in videosdk.yaml",
|
|
294
780
|
)
|
|
295
|
-
|
|
781
|
+
|
|
782
|
+
deployment_id = get_config_option(
|
|
783
|
+
deployment_id,
|
|
784
|
+
["deploy", "id"],
|
|
785
|
+
required=True,
|
|
786
|
+
fail_message="--deployment-id not provided and 'deploy.id' not found in videosdk.yaml",
|
|
787
|
+
)
|
|
788
|
+
print_key_value("Agent ID", agent_id)
|
|
789
|
+
print_key_value("Deployment ID", deployment_id)
|
|
790
|
+
|
|
296
791
|
try:
|
|
297
|
-
asyncio.run(
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
title="Deactivating Deployment",
|
|
301
|
-
duration=2.0,
|
|
302
|
-
))
|
|
303
|
-
console.print("[bold green]Deployment deactivated successfully.[/bold green]")
|
|
792
|
+
asyncio.run(
|
|
793
|
+
list_versions_manager(agent_id, deployment_id, page, per_page, int(sort))
|
|
794
|
+
)
|
|
304
795
|
except Exception as e:
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
@
|
|
309
|
-
@click.option("--
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
796
|
+
print_error(str(e))
|
|
797
|
+
|
|
798
|
+
|
|
799
|
+
@version_cli.command(name="update")
|
|
800
|
+
@click.option("--version-id", "-v", required=True, help="Version ID to update")
|
|
801
|
+
@click.option("--min-replica", type=click.IntRange(min=0), help="New minimum replicas")
|
|
802
|
+
@click.option(
|
|
803
|
+
"--max-replica", type=click.IntRange(min=0, max=50), help="New maximum replicas"
|
|
804
|
+
)
|
|
805
|
+
@click.option("--profile", help="New compute profile: cpu-small, cpu-medium, cpu-large")
|
|
806
|
+
@click.option("--image-pull-secret", help="New image pull secret name")
|
|
807
|
+
@click.option(
|
|
808
|
+
"--agent-id",
|
|
809
|
+
default=None,
|
|
810
|
+
help="Agent ID (reads from videosdk.yaml if not provided)",
|
|
811
|
+
)
|
|
812
|
+
@click.option("--env-secret", help="New environment secret name")
|
|
813
|
+
def version_update(
|
|
814
|
+
version_id,
|
|
815
|
+
min_replica,
|
|
816
|
+
max_replica,
|
|
817
|
+
profile,
|
|
818
|
+
image_pull_secret,
|
|
819
|
+
agent_id,
|
|
820
|
+
env_secret,
|
|
821
|
+
):
|
|
822
|
+
"""
|
|
823
|
+
Update an existing version configuration.
|
|
824
|
+
|
|
825
|
+
Modify replica counts, profile, or secrets for a running version.
|
|
826
|
+
|
|
827
|
+
\b
|
|
828
|
+
Examples:
|
|
829
|
+
$ videosdk agent version update -v ver123 --min-replica 2 --max-replica 10
|
|
830
|
+
$ videosdk agent version update -v ver123 --profile cpu-large
|
|
831
|
+
$ videosdk agent version update -v ver123 --env-secret new-secrets
|
|
832
|
+
"""
|
|
833
|
+
print_header("Updating Version")
|
|
834
|
+
|
|
313
835
|
agent_id = get_config_option(
|
|
314
836
|
agent_id,
|
|
315
|
-
[
|
|
837
|
+
["agent", "id"],
|
|
316
838
|
required=True,
|
|
317
|
-
fail_message="--agent-id not provided and 'agent.id' not found in videosdk.yaml"
|
|
839
|
+
fail_message="--agent-id not provided and 'agent.id' not found in videosdk.yaml",
|
|
318
840
|
)
|
|
841
|
+
|
|
842
|
+
if min_replica is not None:
|
|
843
|
+
print_key_value("Min Replicas", str(min_replica))
|
|
844
|
+
if max_replica is not None:
|
|
845
|
+
print_key_value("Max Replicas", str(max_replica))
|
|
846
|
+
if profile:
|
|
847
|
+
print_key_value("Profile", profile)
|
|
848
|
+
if env_secret:
|
|
849
|
+
print_key_value("Env Secret", env_secret)
|
|
850
|
+
if image_pull_secret:
|
|
851
|
+
print_key_value("Image Pull Secret", image_pull_secret)
|
|
852
|
+
|
|
319
853
|
client = DeploymentClient()
|
|
320
854
|
try:
|
|
321
|
-
asyncio.run(
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
855
|
+
asyncio.run(
|
|
856
|
+
run_with_progress(
|
|
857
|
+
client.update_version(
|
|
858
|
+
version_id=version_id,
|
|
859
|
+
image_cr=None,
|
|
860
|
+
image_url=None,
|
|
861
|
+
env_secret=env_secret,
|
|
862
|
+
image_pull_secret=image_pull_secret,
|
|
863
|
+
min_replica=min_replica,
|
|
864
|
+
max_replica=max_replica,
|
|
865
|
+
profile=profile,
|
|
866
|
+
),
|
|
867
|
+
console=console,
|
|
868
|
+
title="Updating Version",
|
|
869
|
+
duration=5.0,
|
|
870
|
+
)
|
|
871
|
+
)
|
|
872
|
+
print_success("Version updated successfully")
|
|
873
|
+
except KeyboardInterrupt:
|
|
874
|
+
print_warning("Version update cancelled by user")
|
|
875
|
+
raise click.Abort()
|
|
328
876
|
except Exception as e:
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
@
|
|
333
|
-
@click.option("--
|
|
334
|
-
@click.option(
|
|
335
|
-
|
|
336
|
-
|
|
877
|
+
print_error(f"Version update failed: {e}")
|
|
878
|
+
|
|
879
|
+
|
|
880
|
+
@version_cli.command(name="activate")
|
|
881
|
+
@click.option("--version-id", "-v", required=True, help="Version ID to activate")
|
|
882
|
+
@click.option(
|
|
883
|
+
"--agent-id",
|
|
884
|
+
default=None,
|
|
885
|
+
help="Agent ID (reads from videosdk.yaml if not provided)",
|
|
886
|
+
)
|
|
887
|
+
def version_activate(version_id, agent_id):
|
|
888
|
+
"""
|
|
889
|
+
Activate a version.
|
|
890
|
+
|
|
891
|
+
Enables a previously deactivated version to start receiving traffic.
|
|
892
|
+
|
|
893
|
+
\b
|
|
894
|
+
Example:
|
|
895
|
+
$ videosdk agent version activate -v ver123
|
|
896
|
+
"""
|
|
897
|
+
print_header("Activating Version")
|
|
898
|
+
|
|
337
899
|
agent_id = get_config_option(
|
|
338
900
|
agent_id,
|
|
339
|
-
[
|
|
901
|
+
["agent", "id"],
|
|
340
902
|
required=True,
|
|
341
|
-
fail_message="--agent-id not provided and 'agent.id' not found in videosdk.yaml"
|
|
903
|
+
fail_message="--agent-id not provided and 'agent.id' not found in videosdk.yaml",
|
|
342
904
|
)
|
|
905
|
+
|
|
343
906
|
client = DeploymentClient()
|
|
344
907
|
try:
|
|
345
|
-
asyncio.run(
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
908
|
+
asyncio.run(
|
|
909
|
+
run_with_progress(
|
|
910
|
+
client.activate_version(version_id=version_id),
|
|
911
|
+
console=console,
|
|
912
|
+
title="Activating Version",
|
|
913
|
+
duration=2.0,
|
|
914
|
+
)
|
|
915
|
+
)
|
|
916
|
+
print_success("Version activated successfully")
|
|
352
917
|
except Exception as e:
|
|
353
|
-
|
|
918
|
+
print_error(f"Failed to activate version: {e}")
|
|
919
|
+
|
|
920
|
+
|
|
921
|
+
@version_cli.command(name="deactivate")
|
|
922
|
+
@click.option("--version-id", "-v", required=True, help="Version ID to deactivate")
|
|
923
|
+
@click.option(
|
|
924
|
+
"--force",
|
|
925
|
+
is_flag=True,
|
|
926
|
+
default=False,
|
|
927
|
+
help="Force deactivate even with active sessions",
|
|
928
|
+
)
|
|
929
|
+
@click.option(
|
|
930
|
+
"--agent-id",
|
|
931
|
+
default=None,
|
|
932
|
+
help="Agent ID (reads from videosdk.yaml if not provided)",
|
|
933
|
+
)
|
|
934
|
+
def version_deactivate(version_id, force, agent_id):
|
|
935
|
+
"""
|
|
936
|
+
Deactivate a version.
|
|
354
937
|
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
938
|
+
Stops a version from receiving new traffic. Use --force to
|
|
939
|
+
deactivate even if there are active sessions.
|
|
940
|
+
|
|
941
|
+
\b
|
|
942
|
+
Examples:
|
|
943
|
+
$ videosdk agent version deactivate -v ver123
|
|
944
|
+
$ videosdk agent version deactivate -v ver123 --force
|
|
945
|
+
"""
|
|
946
|
+
print_header("Deactivating Version")
|
|
947
|
+
|
|
948
|
+
agent_id = get_config_option(
|
|
949
|
+
agent_id,
|
|
950
|
+
["agent", "id"],
|
|
951
|
+
required=True,
|
|
952
|
+
fail_message="--agent-id not provided and 'agent.id' not found in videosdk.yaml",
|
|
953
|
+
)
|
|
359
954
|
|
|
360
955
|
client = DeploymentClient()
|
|
361
956
|
try:
|
|
362
|
-
asyncio.run(
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
957
|
+
response = asyncio.run(
|
|
958
|
+
run_with_progress(
|
|
959
|
+
client.deactivate_version(version_id=version_id, force=force),
|
|
960
|
+
console=console,
|
|
961
|
+
title="Deactivating Version",
|
|
962
|
+
duration=2.0,
|
|
963
|
+
)
|
|
964
|
+
)
|
|
965
|
+
print_success(response["message"])
|
|
369
966
|
except Exception as e:
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
@
|
|
374
|
-
@click.option("--
|
|
375
|
-
@click.option(
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
967
|
+
print_error(f"Failed to deactivate version: {e}")
|
|
968
|
+
|
|
969
|
+
|
|
970
|
+
@version_cli.command(name="status")
|
|
971
|
+
@click.option("--version-id", "-v", required=True, help="Version ID to check")
|
|
972
|
+
@click.option(
|
|
973
|
+
"--agent-id",
|
|
974
|
+
default=None,
|
|
975
|
+
help="Agent ID (reads from videosdk.yaml if not provided)",
|
|
976
|
+
)
|
|
977
|
+
def version_status(version_id, agent_id):
|
|
978
|
+
"""
|
|
979
|
+
Get the current status of a version.
|
|
980
|
+
|
|
981
|
+
Shows whether the version is active, replica counts, and health status.
|
|
982
|
+
|
|
983
|
+
\b
|
|
984
|
+
Example:
|
|
985
|
+
$ videosdk agent version status -v ver123
|
|
986
|
+
"""
|
|
987
|
+
print_header("Getting Version Status")
|
|
988
|
+
|
|
989
|
+
agent_id = get_config_option(
|
|
381
990
|
agent_id,
|
|
382
|
-
[
|
|
991
|
+
["agent", "id"],
|
|
383
992
|
required=True,
|
|
384
|
-
fail_message="--agent-id not provided and 'agent.id' not found in videosdk.yaml"
|
|
993
|
+
fail_message="--agent-id not provided and 'agent.id' not found in videosdk.yaml",
|
|
385
994
|
)
|
|
995
|
+
|
|
386
996
|
try:
|
|
387
|
-
asyncio.run(
|
|
388
|
-
|
|
389
|
-
)
|
|
390
|
-
console.print(f"[bold green]Agents listed successfully.[/bold green]")
|
|
997
|
+
asyncio.run(describe_version_manager(agent_id, version_id))
|
|
998
|
+
print_info("Next step: Start a session")
|
|
999
|
+
console.print(f" [bold]videosdk agent session start -v {version_id}[/bold]")
|
|
391
1000
|
except Exception as e:
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
@
|
|
396
|
-
@click.option("--
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
1001
|
+
print_error(str(e))
|
|
1002
|
+
|
|
1003
|
+
|
|
1004
|
+
@version_cli.command(name="describe")
|
|
1005
|
+
@click.option("--version-id", "-v", required=True, help="Version ID to describe")
|
|
1006
|
+
@click.option(
|
|
1007
|
+
"--agent-id",
|
|
1008
|
+
default=None,
|
|
1009
|
+
help="Agent ID (reads from videosdk.yaml if not provided)",
|
|
1010
|
+
)
|
|
1011
|
+
def version_describe(version_id, agent_id):
|
|
1012
|
+
"""
|
|
1013
|
+
Get detailed information about a version.
|
|
1014
|
+
|
|
1015
|
+
Shows complete version configuration including image, replicas,
|
|
1016
|
+
profile, secrets, and creation time.
|
|
1017
|
+
|
|
1018
|
+
\b
|
|
1019
|
+
Example:
|
|
1020
|
+
$ videosdk agent version describe -v ver123
|
|
1021
|
+
"""
|
|
1022
|
+
print_header("Describing Version")
|
|
1023
|
+
|
|
1024
|
+
agent_id = get_config_option(
|
|
401
1025
|
agent_id,
|
|
402
|
-
[
|
|
1026
|
+
["agent", "id"],
|
|
403
1027
|
required=True,
|
|
404
|
-
fail_message="--agent-id not provided and 'agent.id' not found in videosdk.yaml"
|
|
1028
|
+
fail_message="--agent-id not provided and 'agent.id' not found in videosdk.yaml",
|
|
405
1029
|
)
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
1030
|
+
|
|
1031
|
+
try:
|
|
1032
|
+
asyncio.run(describe_version_manager(agent_id, version_id))
|
|
1033
|
+
except Exception as e:
|
|
1034
|
+
print_error(str(e))
|
|
1035
|
+
|
|
1036
|
+
|
|
1037
|
+
# Add version subgroup to agent
|
|
1038
|
+
agent_cli.add_command(version_cli, name="version")
|
|
1039
|
+
|
|
1040
|
+
|
|
1041
|
+
# =============================================================================
|
|
1042
|
+
# SESSIONS SUBGROUP
|
|
1043
|
+
# =============================================================================
|
|
1044
|
+
@click.group()
|
|
1045
|
+
def sessions_cli():
|
|
1046
|
+
"""
|
|
1047
|
+
Manage agent sessions.
|
|
1048
|
+
|
|
1049
|
+
View and filter sessions for your agents.
|
|
1050
|
+
|
|
1051
|
+
\b
|
|
1052
|
+
Commands:
|
|
1053
|
+
list List all sessions for an agent
|
|
1054
|
+
"""
|
|
1055
|
+
pass
|
|
1056
|
+
|
|
1057
|
+
|
|
1058
|
+
@sessions_cli.command(name="list")
|
|
1059
|
+
@click.option(
|
|
1060
|
+
"--agent-id",
|
|
1061
|
+
default=None,
|
|
1062
|
+
help="Agent ID (reads from videosdk.yaml if not provided)",
|
|
1063
|
+
)
|
|
1064
|
+
@click.option("--version-id", "-v", help="Filter by Version ID")
|
|
1065
|
+
@click.option("--room-id", help="Filter by Room ID")
|
|
1066
|
+
@click.option("--session-id", help="Filter by Session ID")
|
|
1067
|
+
@click.option(
|
|
1068
|
+
"--page",
|
|
1069
|
+
default=1,
|
|
1070
|
+
type=click.IntRange(min=1),
|
|
1071
|
+
help="Page number (default: 1)",
|
|
1072
|
+
)
|
|
1073
|
+
@click.option(
|
|
1074
|
+
"--per-page",
|
|
1075
|
+
default=10,
|
|
1076
|
+
type=click.IntRange(min=1, max=100),
|
|
1077
|
+
help="Items per page (default: 10)",
|
|
1078
|
+
)
|
|
1079
|
+
@click.option(
|
|
1080
|
+
"--sort",
|
|
1081
|
+
default=-1,
|
|
1082
|
+
type=click.Choice(["1", "-1"]),
|
|
1083
|
+
help="Sort order: 1 (oldest first) or -1 (newest first, default)",
|
|
1084
|
+
)
|
|
1085
|
+
def sessions_list(agent_id, version_id, room_id, session_id, page, per_page, sort):
|
|
1086
|
+
"""
|
|
1087
|
+
List all sessions for an agent.
|
|
1088
|
+
|
|
1089
|
+
Shows a table of sessions with their status, room, and version info.
|
|
1090
|
+
Supports filtering by version, room, and session IDs.
|
|
1091
|
+
|
|
1092
|
+
\b
|
|
1093
|
+
Examples:
|
|
1094
|
+
$ videosdk agent sessions list
|
|
1095
|
+
$ videosdk agent sessions list --agent-id abc123
|
|
1096
|
+
$ videosdk agent sessions list --version-id ver123
|
|
1097
|
+
$ videosdk agent sessions list --page 2 --per-page 20
|
|
1098
|
+
$ videosdk agent sessions list --sort 1 # oldest first
|
|
1099
|
+
"""
|
|
1100
|
+
print_header("Listing Sessions")
|
|
1101
|
+
|
|
1102
|
+
agent_id = get_config_option(
|
|
1103
|
+
agent_id,
|
|
1104
|
+
["agent", "id"],
|
|
1105
|
+
required=True,
|
|
1106
|
+
fail_message="--agent-id not provided and 'agent.id' not found in videosdk.yaml",
|
|
1107
|
+
)
|
|
1108
|
+
deployment_id = get_config_option(
|
|
1109
|
+
None,
|
|
1110
|
+
["deploy", "id"],
|
|
1111
|
+
required=True,
|
|
1112
|
+
fail_message="'deploy.id' not found in videosdk.yaml",
|
|
411
1113
|
)
|
|
1114
|
+
print_key_value("Agent ID", agent_id)
|
|
1115
|
+
print_key_value("Deployment ID", deployment_id)
|
|
412
1116
|
try:
|
|
413
1117
|
asyncio.run(
|
|
414
|
-
|
|
1118
|
+
list_sessions_manager(
|
|
1119
|
+
agent_id=agent_id,
|
|
1120
|
+
deployment_id=deployment_id,
|
|
1121
|
+
version_id=version_id,
|
|
1122
|
+
room_id=room_id,
|
|
1123
|
+
session_id=session_id,
|
|
1124
|
+
page=page,
|
|
1125
|
+
per_page=per_page,
|
|
1126
|
+
sort=int(sort),
|
|
1127
|
+
)
|
|
415
1128
|
)
|
|
416
1129
|
except Exception as e:
|
|
417
|
-
|
|
1130
|
+
print_error(str(e))
|
|
1131
|
+
|
|
1132
|
+
|
|
1133
|
+
# Add sessions subgroup to agent
|
|
1134
|
+
agent_cli.add_command(sessions_cli, name="sessions")
|
|
1135
|
+
|
|
1136
|
+
|
|
1137
|
+
# =============================================================================
|
|
1138
|
+
# SECRETS SUBGROUP
|
|
1139
|
+
# =============================================================================
|
|
1140
|
+
@click.group(invoke_without_command=True)
|
|
1141
|
+
# @click.argument("name", required=False, default=None)
|
|
1142
|
+
@click.pass_context
|
|
1143
|
+
# def secrets_cli(ctx, name):
|
|
1144
|
+
def secrets_cli(ctx):
|
|
1145
|
+
"""
|
|
1146
|
+
Manage agent secrets.
|
|
1147
|
+
|
|
1148
|
+
Create, update, and manage secret sets for your agents.
|
|
1149
|
+
Secrets are securely stored and injected as environment variables.
|
|
418
1150
|
|
|
1151
|
+
\b
|
|
1152
|
+
Usage:
|
|
1153
|
+
videosdk agent secrets list List all secrets
|
|
1154
|
+
videosdk agent secrets create <name> [--file .env] Create a secret
|
|
1155
|
+
videosdk agent secrets add <name> Add keys to secret
|
|
1156
|
+
videosdk agent secrets remove <name> Remove keys from secret
|
|
1157
|
+
videosdk agent secrets describe <name> Show secret details
|
|
1158
|
+
videosdk agent secrets delete <name> Delete a secret
|
|
1159
|
+
"""
|
|
1160
|
+
ctx.ensure_object(dict)
|
|
419
1161
|
|
|
1162
|
+
# # Handle "videosdk agent secrets list" - when "list" is passed as name
|
|
1163
|
+
# if name == "list" and ctx.invoked_subcommand is None:
|
|
1164
|
+
# try:
|
|
1165
|
+
# print_header("Listing Secrets")
|
|
1166
|
+
# asyncio.run(list_secret_manager())
|
|
1167
|
+
# except Exception as e:
|
|
1168
|
+
# print_error(str(e))
|
|
1169
|
+
# ctx.exit(0)
|
|
1170
|
+
|
|
1171
|
+
# # If name is provided and subcommand is "list", show error
|
|
1172
|
+
# if name and ctx.invoked_subcommand == "list":
|
|
1173
|
+
# print_error(
|
|
1174
|
+
# "The 'list' command does not take a secret name. Use 'videosdk agent secrets list'"
|
|
1175
|
+
# )
|
|
1176
|
+
# ctx.exit(1)
|
|
1177
|
+
|
|
1178
|
+
# # If name is provided but no subcommand, show error
|
|
1179
|
+
# if name and ctx.invoked_subcommand is None:
|
|
1180
|
+
# print_error(
|
|
1181
|
+
# f"Missing subcommand for secret '{name}'. "
|
|
1182
|
+
# "Use one of: create, add, remove, describe, delete"
|
|
1183
|
+
# )
|
|
1184
|
+
# console.print()
|
|
1185
|
+
# console.print("Examples:")
|
|
1186
|
+
# console.print(f" videosdk agent secrets create {name} ")
|
|
1187
|
+
# console.print(f" videosdk agent secrets describe {name} ")
|
|
1188
|
+
# console.print(f" videosdk agent secrets delete {name} ")
|
|
1189
|
+
# ctx.exit(1)
|
|
1190
|
+
|
|
1191
|
+
# ctx.obj["secret_name"] = name
|
|
1192
|
+
|
|
1193
|
+
|
|
1194
|
+
@secrets_cli.command(name="list")
|
|
1195
|
+
@click.pass_context
|
|
1196
|
+
def secrets_list(ctx):
|
|
1197
|
+
"""
|
|
1198
|
+
List all secret sets.
|
|
1199
|
+
|
|
1200
|
+
Shows a table of all secrets with their names, IDs, and types.
|
|
1201
|
+
|
|
1202
|
+
\b
|
|
1203
|
+
Example:
|
|
1204
|
+
$ videosdk agent secrets list
|
|
1205
|
+
"""
|
|
1206
|
+
# Check if a name was provided (should not be)
|
|
1207
|
+
if ctx.obj.get("secret_name"):
|
|
1208
|
+
print_error(
|
|
1209
|
+
"The 'list' command does not take a secret name. Use 'videosdk agent secrets list'"
|
|
1210
|
+
)
|
|
1211
|
+
ctx.exit(1)
|
|
1212
|
+
|
|
1213
|
+
try:
|
|
1214
|
+
print_header("Listing Secrets")
|
|
1215
|
+
asyncio.run(list_secret_manager())
|
|
1216
|
+
except Exception as e:
|
|
1217
|
+
print_error(str(e))
|
|
1218
|
+
|
|
1219
|
+
|
|
1220
|
+
@secrets_cli.command(name="create")
|
|
1221
|
+
@click.argument("name")
|
|
1222
|
+
@click.option(
|
|
1223
|
+
"--file",
|
|
1224
|
+
"-f",
|
|
1225
|
+
"file_path",
|
|
1226
|
+
default=None,
|
|
1227
|
+
help="Path to .env file with key=value pairs",
|
|
1228
|
+
)
|
|
1229
|
+
@click.option("--region", default=None, help="Region for storing secrets")
|
|
1230
|
+
@click.pass_context
|
|
1231
|
+
def secrets_create(ctx, name, file_path, region):
|
|
1232
|
+
"""
|
|
1233
|
+
Create a new secret set.
|
|
1234
|
+
|
|
1235
|
+
Creates a new secret set with the given name. Provide secrets via
|
|
1236
|
+
a .env file or enter them interactively.
|
|
1237
|
+
|
|
1238
|
+
\b
|
|
1239
|
+
Examples:
|
|
1240
|
+
$ videosdk agent secrets create my-secrets --file .env
|
|
1241
|
+
$ videosdk agent secrets create my-secrets # interactive mode
|
|
1242
|
+
"""
|
|
1243
|
+
# name = ctx.obj.get("secret_name")
|
|
1244
|
+
if not name:
|
|
1245
|
+
print_error("Secret name is required")
|
|
1246
|
+
return
|
|
1247
|
+
try:
|
|
1248
|
+
print_header("Creating Secret")
|
|
1249
|
+
response = asyncio.run(secret_set_manager(name, file_path))
|
|
1250
|
+
print_success(f"Secret '{name}' created successfully")
|
|
1251
|
+
|
|
1252
|
+
# Extract secret ID from response
|
|
1253
|
+
secret_id = None
|
|
1254
|
+
if response:
|
|
1255
|
+
# Try different possible response formats
|
|
1256
|
+
secret_id = (
|
|
1257
|
+
response.get("secretId")
|
|
1258
|
+
or response.get("id")
|
|
1259
|
+
or response.get("data", {}).get("secretId")
|
|
1260
|
+
or response.get("data", {}).get("id")
|
|
1261
|
+
)
|
|
1262
|
+
|
|
1263
|
+
if secret_id:
|
|
1264
|
+
# Save secret ID to videosdk.yaml
|
|
1265
|
+
from videosdk_cli.utils.videosdk_yaml_helper import (
|
|
1266
|
+
update_agent_config,
|
|
1267
|
+
SecretsConfig,
|
|
1268
|
+
)
|
|
1269
|
+
|
|
1270
|
+
secrets_config = SecretsConfig(env=secret_id)
|
|
1271
|
+
update_agent_config(
|
|
1272
|
+
app_dir=Path(os.getcwd()),
|
|
1273
|
+
secrets_config=secrets_config,
|
|
1274
|
+
)
|
|
1275
|
+
print_success(f"Secret ID saved to videosdk.yaml: {secret_id}")
|
|
1276
|
+
else:
|
|
1277
|
+
print_warning(
|
|
1278
|
+
"Could not extract secret ID from response. Secret created but not saved to yaml."
|
|
1279
|
+
)
|
|
1280
|
+
except click.Abort:
|
|
1281
|
+
print_warning("Cancelled. No secrets were saved.")
|
|
1282
|
+
except Exception as e:
|
|
1283
|
+
print_error(str(e))
|
|
1284
|
+
|
|
1285
|
+
|
|
1286
|
+
@secrets_cli.command(name="add")
|
|
1287
|
+
@click.argument("name")
|
|
1288
|
+
@click.pass_context
|
|
1289
|
+
def secrets_add(ctx, name):
|
|
1290
|
+
"""
|
|
1291
|
+
Add keys to an existing secret set.
|
|
1292
|
+
|
|
1293
|
+
Interactively add new key-value pairs to an existing secret.
|
|
1294
|
+
|
|
1295
|
+
\b
|
|
1296
|
+
Example:
|
|
1297
|
+
$ videosdk agent secrets add my-secrets
|
|
1298
|
+
"""
|
|
1299
|
+
# name = ctx.obj.get("secret_name")
|
|
1300
|
+
if not name:
|
|
1301
|
+
print_error("Secret name is required")
|
|
1302
|
+
return
|
|
1303
|
+
try:
|
|
1304
|
+
print_header("Adding to Secret")
|
|
1305
|
+
asyncio.run(add_secret_set(name))
|
|
1306
|
+
print_success(f"Keys added to secret '{name}' successfully")
|
|
1307
|
+
except Exception as e:
|
|
1308
|
+
print_error(str(e))
|
|
1309
|
+
|
|
1310
|
+
|
|
1311
|
+
@secrets_cli.command(name="remove")
|
|
1312
|
+
@click.argument("name")
|
|
1313
|
+
@click.pass_context
|
|
1314
|
+
def secrets_remove(ctx, name):
|
|
1315
|
+
"""
|
|
1316
|
+
Remove keys from a secret set.
|
|
1317
|
+
|
|
1318
|
+
Interactively select and remove specific keys from a secret.
|
|
1319
|
+
|
|
1320
|
+
\b
|
|
1321
|
+
Example:
|
|
1322
|
+
$ videosdk agent secrets remove my-secrets
|
|
1323
|
+
"""
|
|
1324
|
+
# name = ctx.obj.get("secret_name")
|
|
1325
|
+
if not name:
|
|
1326
|
+
print_error("Secret name is required")
|
|
1327
|
+
return
|
|
1328
|
+
try:
|
|
1329
|
+
print_header("Removing Keys from Secret")
|
|
1330
|
+
asyncio.run(remove_secret_set_key(name))
|
|
1331
|
+
except Exception as e:
|
|
1332
|
+
print_error(str(e))
|
|
1333
|
+
|
|
1334
|
+
|
|
1335
|
+
@secrets_cli.command(name="describe")
|
|
1336
|
+
@click.argument("name")
|
|
1337
|
+
@click.pass_context
|
|
1338
|
+
def secrets_describe(ctx, name):
|
|
1339
|
+
"""
|
|
1340
|
+
Show details of a secret set.
|
|
1341
|
+
|
|
1342
|
+
Displays the secret name, ID, type, and list of keys (values hidden).
|
|
1343
|
+
|
|
1344
|
+
\b
|
|
1345
|
+
Example:
|
|
1346
|
+
$ videosdk agent secrets describe my-secrets
|
|
1347
|
+
"""
|
|
1348
|
+
# name = ctx.obj.get("secret_name")
|
|
1349
|
+
if not name:
|
|
1350
|
+
print_error("Secret name is required")
|
|
1351
|
+
return
|
|
1352
|
+
try:
|
|
1353
|
+
print_header("Describing Secret")
|
|
1354
|
+
asyncio.run(describe_secret_set(name))
|
|
1355
|
+
except Exception as e:
|
|
1356
|
+
print_error(str(e))
|
|
1357
|
+
|
|
1358
|
+
|
|
1359
|
+
@secrets_cli.command(name="delete")
|
|
1360
|
+
@click.argument("name")
|
|
1361
|
+
@click.pass_context
|
|
1362
|
+
def secrets_delete(ctx, name):
|
|
1363
|
+
"""
|
|
1364
|
+
Delete a secret set.
|
|
1365
|
+
|
|
1366
|
+
Permanently deletes the secret set and all its keys.
|
|
1367
|
+
This action cannot be undone.
|
|
1368
|
+
|
|
1369
|
+
\b
|
|
1370
|
+
Example:
|
|
1371
|
+
$ videosdk agent secrets delete my-secrets
|
|
1372
|
+
"""
|
|
1373
|
+
# name = ctx.obj.get("secret_name")
|
|
1374
|
+
if not name:
|
|
1375
|
+
print_error("Secret name is required")
|
|
1376
|
+
return
|
|
1377
|
+
try:
|
|
1378
|
+
print_header("Deleting Secret")
|
|
1379
|
+
asyncio.run(remove_secret_set(name))
|
|
1380
|
+
print_success(f"Secret '{name}' deleted successfully")
|
|
1381
|
+
except Exception as e:
|
|
1382
|
+
print_error(str(e))
|
|
1383
|
+
|
|
1384
|
+
|
|
1385
|
+
# Add secrets subgroup to agent
|
|
1386
|
+
agent_cli.add_command(secrets_cli, name="secrets")
|
|
1387
|
+
|
|
1388
|
+
|
|
1389
|
+
# =============================================================================
|
|
1390
|
+
# IMAGE PULL SECRET
|
|
1391
|
+
# =============================================================================
|
|
420
1392
|
@agent_cli.command(name="image-pull-secret")
|
|
421
|
-
@click.
|
|
422
|
-
|
|
1393
|
+
@click.argument("name")
|
|
1394
|
+
@click.option("--region", default=None, help="Region for storing the secret")
|
|
1395
|
+
def image_pull_secret(name, region):
|
|
1396
|
+
"""
|
|
1397
|
+
Create an image pull secret for private container registries.
|
|
1398
|
+
|
|
1399
|
+
Stores registry credentials securely for pulling private Docker images.
|
|
1400
|
+
You will be prompted for server, username, and password.
|
|
1401
|
+
|
|
1402
|
+
\b
|
|
1403
|
+
Examples:
|
|
1404
|
+
$ videosdk agent image-pull-secret my-registry-creds
|
|
1405
|
+
$ videosdk agent image-pull-secret ghcr-secret --region us-east
|
|
1406
|
+
"""
|
|
1407
|
+
try:
|
|
1408
|
+
print_header("Creating Image Pull Secret")
|
|
1409
|
+
asyncio.run(image_pull_secret_manager(name))
|
|
1410
|
+
print_success(f"Image pull secret '{name}' created successfully")
|
|
1411
|
+
except Exception as e:
|
|
1412
|
+
print_error(str(e))
|
|
1413
|
+
|
|
1414
|
+
|
|
1415
|
+
# =============================================================================
|
|
1416
|
+
# SESSION SUBGROUP
|
|
1417
|
+
# =============================================================================
|
|
1418
|
+
@click.group()
|
|
1419
|
+
def session_cli():
|
|
1420
|
+
"""
|
|
1421
|
+
Manage agent sessions.
|
|
1422
|
+
|
|
1423
|
+
Start and stop individual agent sessions in rooms.
|
|
1424
|
+
|
|
1425
|
+
\b
|
|
1426
|
+
Commands:
|
|
1427
|
+
start Start an agent in a room
|
|
1428
|
+
stop Stop an agent session
|
|
1429
|
+
"""
|
|
1430
|
+
pass
|
|
1431
|
+
|
|
1432
|
+
|
|
1433
|
+
@session_cli.command(name="start")
|
|
1434
|
+
@click.option("--version-id", "-v", default=None, help="Version ID to use")
|
|
1435
|
+
@click.option(
|
|
1436
|
+
"--room-id",
|
|
1437
|
+
"-r",
|
|
1438
|
+
default=None,
|
|
1439
|
+
help="Room ID to join (creates new room if not provided)",
|
|
1440
|
+
)
|
|
1441
|
+
@click.option(
|
|
1442
|
+
"--agent-id",
|
|
1443
|
+
"-a",
|
|
1444
|
+
default=None,
|
|
1445
|
+
help="Agent ID (reads from videosdk.yaml if not provided)",
|
|
1446
|
+
)
|
|
1447
|
+
def session_start(version_id, room_id, agent_id):
|
|
1448
|
+
"""
|
|
1449
|
+
Start an agent session in a room.
|
|
1450
|
+
|
|
1451
|
+
Dispatches an agent to join the specified room. If no room-id is
|
|
1452
|
+
provided, a new room will be created automatically.
|
|
1453
|
+
|
|
1454
|
+
\b
|
|
1455
|
+
Examples:
|
|
1456
|
+
$ videosdk agent session start -r room-abc # uses latest version of agent if not provided
|
|
1457
|
+
$ videosdk agent session start -v ver123 # creates new room
|
|
1458
|
+
$ videosdk agent session start -v ver123 -r room-abc
|
|
1459
|
+
$ videosdk agent session start # uses latest version
|
|
1460
|
+
"""
|
|
1461
|
+
print_header("Starting Session")
|
|
1462
|
+
|
|
1463
|
+
agent_id = get_config_option(
|
|
1464
|
+
agent_id,
|
|
1465
|
+
["agent", "id"],
|
|
1466
|
+
required=True,
|
|
1467
|
+
fail_message="--agent-id not provided and 'agent.id' not found in videosdk.yaml",
|
|
1468
|
+
)
|
|
1469
|
+
|
|
1470
|
+
client = DeploymentClient()
|
|
1471
|
+
try:
|
|
1472
|
+
result = asyncio.run(
|
|
1473
|
+
run_with_progress(
|
|
1474
|
+
client.agent_start(
|
|
1475
|
+
version_id=version_id, agent_id=agent_id, meeting_id=room_id
|
|
1476
|
+
),
|
|
1477
|
+
console=console,
|
|
1478
|
+
title="Starting Session",
|
|
1479
|
+
duration=30.0,
|
|
1480
|
+
)
|
|
1481
|
+
)
|
|
1482
|
+
print_success("Session started successfully")
|
|
1483
|
+
|
|
1484
|
+
# Extract room_id from result
|
|
1485
|
+
started_room_id = result.get("roomId") if result else room_id
|
|
1486
|
+
if started_room_id:
|
|
1487
|
+
print_key_value("Room ID", started_room_id)
|
|
1488
|
+
print_info("Useful commands:")
|
|
1489
|
+
console.print(f" [bold]View logs:[/bold] videosdk agent version logs")
|
|
1490
|
+
console.print(
|
|
1491
|
+
f" [bold]Stop session:[/bold] videosdk agent session stop -r {started_room_id}"
|
|
1492
|
+
)
|
|
1493
|
+
except Exception as e:
|
|
1494
|
+
print_error(f"Failed to start session: {e}")
|
|
1495
|
+
|
|
1496
|
+
|
|
1497
|
+
@session_cli.command(name="stop")
|
|
1498
|
+
@click.option("--room-id", "-r", default=None, help="Room ID of the session")
|
|
1499
|
+
@click.option("--session-id", "-s", default=None, help="Session ID to stop")
|
|
1500
|
+
def session_stop(room_id, session_id):
|
|
1501
|
+
"""
|
|
1502
|
+
Stop an agent session.
|
|
1503
|
+
\b
|
|
1504
|
+
Examples:
|
|
1505
|
+
$ videosdk agent session stop -r room-abc
|
|
1506
|
+
$ videosdk agent session stop -s session-123
|
|
1507
|
+
"""
|
|
1508
|
+
print_header("Stopping Session")
|
|
1509
|
+
|
|
1510
|
+
if not room_id and not session_id:
|
|
1511
|
+
print_error("Either --room-id or --session-id is required")
|
|
1512
|
+
sys.exit(1)
|
|
1513
|
+
|
|
1514
|
+
client = DeploymentClient()
|
|
423
1515
|
try:
|
|
424
1516
|
asyncio.run(
|
|
425
|
-
|
|
1517
|
+
run_with_progress(
|
|
1518
|
+
client.agent_stop(meeting_id=room_id, session_id=session_id),
|
|
1519
|
+
console=console,
|
|
1520
|
+
title="Ending Session",
|
|
1521
|
+
duration=2.0,
|
|
1522
|
+
)
|
|
426
1523
|
)
|
|
1524
|
+
print_success("Session ended successfully")
|
|
427
1525
|
except Exception as e:
|
|
428
|
-
|
|
1526
|
+
print_error(f"Failed to stop session: {e}")
|
|
1527
|
+
|
|
429
1528
|
|
|
430
|
-
|
|
1529
|
+
# Add session subgroup to agent
|
|
1530
|
+
agent_cli.add_command(session_cli, name="session")
|