agentstack-cli 0.6.0rc1__py3-none-manylinux_2_34_aarch64.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.
- agentstack_cli/__init__.py +164 -0
- agentstack_cli/api.py +160 -0
- agentstack_cli/async_typer.py +113 -0
- agentstack_cli/auth_manager.py +242 -0
- agentstack_cli/commands/__init__.py +3 -0
- agentstack_cli/commands/agent.py +1386 -0
- agentstack_cli/commands/build.py +222 -0
- agentstack_cli/commands/connector.py +301 -0
- agentstack_cli/commands/model.py +653 -0
- agentstack_cli/commands/platform/__init__.py +198 -0
- agentstack_cli/commands/platform/base_driver.py +217 -0
- agentstack_cli/commands/platform/lima_driver.py +277 -0
- agentstack_cli/commands/platform/wsl_driver.py +229 -0
- agentstack_cli/commands/self.py +213 -0
- agentstack_cli/commands/server.py +315 -0
- agentstack_cli/commands/user.py +87 -0
- agentstack_cli/configuration.py +79 -0
- agentstack_cli/console.py +25 -0
- agentstack_cli/data/.gitignore +2 -0
- agentstack_cli/data/helm-chart.tgz +0 -0
- agentstack_cli/data/lima-guestagent.Linux-aarch64.gz +0 -0
- agentstack_cli/data/limactl +0 -0
- agentstack_cli/utils.py +389 -0
- agentstack_cli-0.6.0rc1.dist-info/METADATA +107 -0
- agentstack_cli-0.6.0rc1.dist-info/RECORD +27 -0
- agentstack_cli-0.6.0rc1.dist-info/WHEEL +4 -0
- agentstack_cli-0.6.0rc1.dist-info/entry_points.txt +4 -0
|
@@ -0,0 +1,198 @@
|
|
|
1
|
+
# Copyright 2025 © BeeAI a Series of LF Projects, LLC
|
|
2
|
+
# SPDX-License-Identifier: Apache-2.0
|
|
3
|
+
|
|
4
|
+
import datetime
|
|
5
|
+
import functools
|
|
6
|
+
import importlib.resources
|
|
7
|
+
import os
|
|
8
|
+
import pathlib
|
|
9
|
+
import platform
|
|
10
|
+
import shutil
|
|
11
|
+
import sys
|
|
12
|
+
import textwrap
|
|
13
|
+
import typing
|
|
14
|
+
|
|
15
|
+
import httpx
|
|
16
|
+
import typer
|
|
17
|
+
from tenacity import AsyncRetrying, retry_if_exception_type, stop_after_delay, wait_fixed
|
|
18
|
+
|
|
19
|
+
from agentstack_cli.async_typer import AsyncTyper
|
|
20
|
+
from agentstack_cli.commands.platform.base_driver import BaseDriver
|
|
21
|
+
from agentstack_cli.commands.platform.lima_driver import LimaDriver
|
|
22
|
+
from agentstack_cli.commands.platform.wsl_driver import WSLDriver
|
|
23
|
+
from agentstack_cli.configuration import Configuration
|
|
24
|
+
from agentstack_cli.console import console
|
|
25
|
+
from agentstack_cli.utils import verbosity
|
|
26
|
+
|
|
27
|
+
app = AsyncTyper()
|
|
28
|
+
|
|
29
|
+
configuration = Configuration()
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
@functools.cache
|
|
33
|
+
def get_driver(vm_name: str = "agentstack") -> BaseDriver:
|
|
34
|
+
has_lima = (importlib.resources.files("agentstack_cli") / "data" / "limactl").is_file() or shutil.which("limactl")
|
|
35
|
+
has_vz = os.path.exists("/System/Library/Frameworks/Virtualization.framework")
|
|
36
|
+
arch = "aarch64" if platform.machine().lower() == "arm64" else platform.machine().lower()
|
|
37
|
+
has_qemu = bool(shutil.which(f"qemu-system-{arch}"))
|
|
38
|
+
|
|
39
|
+
if platform.system() == "Windows" or shutil.which("wsl.exe"):
|
|
40
|
+
return WSLDriver(vm_name=vm_name)
|
|
41
|
+
elif has_lima and (has_vz or has_qemu):
|
|
42
|
+
return LimaDriver(vm_name=vm_name)
|
|
43
|
+
else:
|
|
44
|
+
console.error("Could not find a compatible VM runtime.")
|
|
45
|
+
if platform.system() == "Darwin":
|
|
46
|
+
console.hint("This version of macOS is unsupported, please update the system.")
|
|
47
|
+
elif platform.system() == "Linux":
|
|
48
|
+
if not has_lima:
|
|
49
|
+
console.hint(
|
|
50
|
+
"This Linux distribution is not suppored by Lima VM binary releases (required: glibc>=2.34). Manually install Lima VM >=1.2.1 through either:\n"
|
|
51
|
+
+ " - Your distribution's package manager, if available (https://repology.org/project/lima/versions)\n"
|
|
52
|
+
+ " - Homebrew, which uses its own separate glibc on Linux (https://brew.sh)\n"
|
|
53
|
+
+ " - Building it yourself, and ensuring that limactl is in PATH (https://lima-vm.io/docs/installation/source/)"
|
|
54
|
+
)
|
|
55
|
+
if not has_qemu:
|
|
56
|
+
console.hint(
|
|
57
|
+
f"QEMU is needed on Linux, please install it and ensure that qemu-system-{arch} is in PATH. Refer to https://www.qemu.org/download/ for instructions."
|
|
58
|
+
)
|
|
59
|
+
sys.exit(1)
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
@app.command("start", help="Start Agent Stack platform. [Local only]")
|
|
63
|
+
async def start(
|
|
64
|
+
set_values_list: typing.Annotated[
|
|
65
|
+
list[str], typer.Option("--set", help="Set Helm chart values using <key>=<value> syntax", default_factory=list)
|
|
66
|
+
],
|
|
67
|
+
import_images: typing.Annotated[
|
|
68
|
+
list[str],
|
|
69
|
+
typer.Option(
|
|
70
|
+
"--import", help="Import an image from a local Docker CLI into Agent Stack platform", default_factory=list
|
|
71
|
+
),
|
|
72
|
+
],
|
|
73
|
+
pull_on_host: typing.Annotated[
|
|
74
|
+
bool,
|
|
75
|
+
typer.Option(
|
|
76
|
+
"--pull-on-host",
|
|
77
|
+
help="Pull images on host Docker daemon and import them instead of pulling inside the VM. Acts as a pull cache layer.",
|
|
78
|
+
),
|
|
79
|
+
] = False,
|
|
80
|
+
values_file: typing.Annotated[
|
|
81
|
+
pathlib.Path | None, typer.Option("-f", help="Set Helm chart values using yaml values file")
|
|
82
|
+
] = None,
|
|
83
|
+
vm_name: typing.Annotated[str, typer.Option(hidden=True)] = "agentstack",
|
|
84
|
+
verbose: typing.Annotated[bool, typer.Option("-v", "--verbose", help="Show verbose output")] = False,
|
|
85
|
+
skip_pull: typing.Annotated[bool, typer.Option(hidden=True)] = False,
|
|
86
|
+
skip_restart_deployments: typing.Annotated[bool, typer.Option(hidden=True)] = False,
|
|
87
|
+
no_wait_for_platform: typing.Annotated[bool, typer.Option(hidden=True)] = False,
|
|
88
|
+
):
|
|
89
|
+
import agentstack_cli.commands.server
|
|
90
|
+
|
|
91
|
+
values_file_path = None
|
|
92
|
+
if values_file:
|
|
93
|
+
values_file_path = pathlib.Path(values_file)
|
|
94
|
+
if not values_file_path.is_file():
|
|
95
|
+
raise FileNotFoundError(f"Values file {values_file} not found.")
|
|
96
|
+
|
|
97
|
+
with verbosity(verbose):
|
|
98
|
+
driver = get_driver(vm_name=vm_name)
|
|
99
|
+
await driver.create_vm()
|
|
100
|
+
await driver.install_tools()
|
|
101
|
+
await driver.deploy(
|
|
102
|
+
set_values_list=set_values_list,
|
|
103
|
+
values_file=values_file_path,
|
|
104
|
+
import_images=import_images,
|
|
105
|
+
pull_on_host=pull_on_host,
|
|
106
|
+
skip_pull=skip_pull,
|
|
107
|
+
skip_restart_deployments=skip_restart_deployments,
|
|
108
|
+
)
|
|
109
|
+
|
|
110
|
+
if not no_wait_for_platform:
|
|
111
|
+
with console.status("Waiting for Agent Stack platform to be ready...", spinner="dots"):
|
|
112
|
+
timeout = datetime.timedelta(minutes=20)
|
|
113
|
+
async with httpx.AsyncClient() as client:
|
|
114
|
+
try:
|
|
115
|
+
async for attempt in AsyncRetrying(
|
|
116
|
+
stop=stop_after_delay(timeout),
|
|
117
|
+
wait=wait_fixed(datetime.timedelta(seconds=1)),
|
|
118
|
+
retry=retry_if_exception_type((httpx.HTTPError, ConnectionError)),
|
|
119
|
+
reraise=True,
|
|
120
|
+
):
|
|
121
|
+
with attempt:
|
|
122
|
+
resp = await client.get("http://localhost:8333/healthcheck")
|
|
123
|
+
resp.raise_for_status()
|
|
124
|
+
except Exception as ex:
|
|
125
|
+
raise ConnectionError(
|
|
126
|
+
f"Server did not start in {timeout}. Please check your internet connection."
|
|
127
|
+
) from ex
|
|
128
|
+
|
|
129
|
+
console.success("Agent Stack platform started successfully!")
|
|
130
|
+
|
|
131
|
+
if any("phoenix.enabled=true" in value.lower() for value in set_values_list):
|
|
132
|
+
console.print(
|
|
133
|
+
textwrap.dedent("""\
|
|
134
|
+
|
|
135
|
+
License Notice:
|
|
136
|
+
When you enable Phoenix, be aware that Arize Phoenix is licensed under the Elastic License v2 (ELv2),
|
|
137
|
+
which has specific terms regarding commercial use and distribution. By enabling Phoenix, you acknowledge
|
|
138
|
+
that you are responsible for ensuring compliance with the ELv2 license terms for your specific use case.
|
|
139
|
+
Please review the Phoenix license (https://github.com/Arize-ai/phoenix/blob/main/LICENSE) before enabling
|
|
140
|
+
this feature in production environments.
|
|
141
|
+
"""),
|
|
142
|
+
style="dim",
|
|
143
|
+
)
|
|
144
|
+
|
|
145
|
+
await agentstack_cli.commands.server.server_login("http://localhost:8333")
|
|
146
|
+
|
|
147
|
+
|
|
148
|
+
@app.command("stop", help="Stop Agent Stack platform. [Local only]")
|
|
149
|
+
async def stop(
|
|
150
|
+
vm_name: typing.Annotated[str, typer.Option(hidden=True)] = "agentstack",
|
|
151
|
+
verbose: typing.Annotated[bool, typer.Option("-v", "--verbose", help="Show verbose output")] = False,
|
|
152
|
+
):
|
|
153
|
+
with verbosity(verbose):
|
|
154
|
+
driver = get_driver(vm_name=vm_name)
|
|
155
|
+
if not await driver.status():
|
|
156
|
+
console.info("Agent Stack platform not found. Nothing to stop.")
|
|
157
|
+
return
|
|
158
|
+
await driver.stop()
|
|
159
|
+
console.success("Agent Stack platform stopped successfully.")
|
|
160
|
+
|
|
161
|
+
|
|
162
|
+
@app.command("delete", help="Delete Agent Stack platform. [Local only]")
|
|
163
|
+
async def delete(
|
|
164
|
+
vm_name: typing.Annotated[str, typer.Option(hidden=True)] = "agentstack",
|
|
165
|
+
verbose: typing.Annotated[bool, typer.Option("-v", "--verbose", help="Show verbose output")] = False,
|
|
166
|
+
):
|
|
167
|
+
with verbosity(verbose):
|
|
168
|
+
driver = get_driver(vm_name=vm_name)
|
|
169
|
+
await driver.delete()
|
|
170
|
+
console.success("Agent Stack platform deleted successfully.")
|
|
171
|
+
|
|
172
|
+
|
|
173
|
+
@app.command("import", help="Import a local docker image into the Agent Stack platform. [Local only]")
|
|
174
|
+
async def import_image_cmd(
|
|
175
|
+
tag: typing.Annotated[str, typer.Argument(help="Docker image tag to import")],
|
|
176
|
+
vm_name: typing.Annotated[str, typer.Option(hidden=True)] = "agentstack",
|
|
177
|
+
verbose: typing.Annotated[bool, typer.Option("-v", "--verbose", help="Show verbose output")] = False,
|
|
178
|
+
):
|
|
179
|
+
with verbosity(verbose):
|
|
180
|
+
driver = get_driver(vm_name=vm_name)
|
|
181
|
+
if (await driver.status()) != "running":
|
|
182
|
+
console.error("Agent Stack platform is not running.")
|
|
183
|
+
sys.exit(1)
|
|
184
|
+
await driver.import_images(tag)
|
|
185
|
+
|
|
186
|
+
|
|
187
|
+
@app.command("exec", help="For debugging -- execute a command inside the Agent Stack platform VM. [Local only]")
|
|
188
|
+
async def exec_cmd(
|
|
189
|
+
command: typing.Annotated[list[str] | None, typer.Argument()] = None,
|
|
190
|
+
vm_name: typing.Annotated[str, typer.Option(hidden=True)] = "agentstack",
|
|
191
|
+
verbose: typing.Annotated[bool, typer.Option("-v", "--verbose", help="Show verbose output")] = False,
|
|
192
|
+
):
|
|
193
|
+
with verbosity(verbose, show_success_status=False):
|
|
194
|
+
driver = get_driver(vm_name=vm_name)
|
|
195
|
+
if (await driver.status()) != "running":
|
|
196
|
+
console.error("Agent Stack platform is not running.")
|
|
197
|
+
sys.exit(1)
|
|
198
|
+
await driver.exec(command or ["/bin/bash"])
|
|
@@ -0,0 +1,217 @@
|
|
|
1
|
+
# Copyright 2025 © BeeAI a Series of LF Projects, LLC
|
|
2
|
+
# SPDX-License-Identifier: Apache-2.0
|
|
3
|
+
|
|
4
|
+
import abc
|
|
5
|
+
import importlib.resources
|
|
6
|
+
import pathlib
|
|
7
|
+
import shlex
|
|
8
|
+
import typing
|
|
9
|
+
from subprocess import CompletedProcess
|
|
10
|
+
from textwrap import dedent
|
|
11
|
+
|
|
12
|
+
import anyio
|
|
13
|
+
import yaml
|
|
14
|
+
from tenacity import AsyncRetrying, stop_after_attempt
|
|
15
|
+
|
|
16
|
+
from agentstack_cli.configuration import Configuration
|
|
17
|
+
from agentstack_cli.utils import merge, run_command
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
class BaseDriver(abc.ABC):
|
|
21
|
+
vm_name: str
|
|
22
|
+
|
|
23
|
+
def __init__(self, vm_name: str = "agentstack"):
|
|
24
|
+
self.vm_name = vm_name
|
|
25
|
+
self.loaded_images: set[str] = set()
|
|
26
|
+
|
|
27
|
+
@abc.abstractmethod
|
|
28
|
+
async def run_in_vm(
|
|
29
|
+
self,
|
|
30
|
+
command: list[str],
|
|
31
|
+
message: str,
|
|
32
|
+
env: dict[str, str] | None = None,
|
|
33
|
+
input: bytes | None = None,
|
|
34
|
+
) -> CompletedProcess[bytes]: ...
|
|
35
|
+
|
|
36
|
+
@abc.abstractmethod
|
|
37
|
+
async def status(self) -> typing.Literal["running"] | str | None: ...
|
|
38
|
+
|
|
39
|
+
@abc.abstractmethod
|
|
40
|
+
async def create_vm(self) -> None: ...
|
|
41
|
+
|
|
42
|
+
@abc.abstractmethod
|
|
43
|
+
async def stop(self) -> None: ...
|
|
44
|
+
|
|
45
|
+
@abc.abstractmethod
|
|
46
|
+
async def delete(self) -> None: ...
|
|
47
|
+
|
|
48
|
+
@abc.abstractmethod
|
|
49
|
+
async def import_images(self, *tags: str) -> None: ...
|
|
50
|
+
|
|
51
|
+
@abc.abstractmethod
|
|
52
|
+
async def import_image_to_internal_registry(self, tag: str) -> None: ...
|
|
53
|
+
|
|
54
|
+
@abc.abstractmethod
|
|
55
|
+
async def exec(self, command: list[str]) -> None: ...
|
|
56
|
+
|
|
57
|
+
async def install_tools(self) -> None:
|
|
58
|
+
# Configure k3s registry for local registry access
|
|
59
|
+
registry_config = dedent(
|
|
60
|
+
"""\
|
|
61
|
+
mirrors:
|
|
62
|
+
"agentstack-registry-svc.default:5001":
|
|
63
|
+
endpoint:
|
|
64
|
+
- "http://localhost:30501"
|
|
65
|
+
configs:
|
|
66
|
+
"agentstack-registry-svc.default:5001":
|
|
67
|
+
tls:
|
|
68
|
+
insecure_skip_verify: true
|
|
69
|
+
"""
|
|
70
|
+
)
|
|
71
|
+
|
|
72
|
+
await self.run_in_vm(
|
|
73
|
+
[
|
|
74
|
+
"sh",
|
|
75
|
+
"-c",
|
|
76
|
+
(
|
|
77
|
+
f"sudo mkdir -p /etc/rancher/k3s /registry-data && "
|
|
78
|
+
f"echo '{registry_config}' | "
|
|
79
|
+
"sudo tee /etc/rancher/k3s/registries.yaml > /dev/null"
|
|
80
|
+
),
|
|
81
|
+
],
|
|
82
|
+
"Configuring k3s registry",
|
|
83
|
+
)
|
|
84
|
+
|
|
85
|
+
await self.run_in_vm(
|
|
86
|
+
[
|
|
87
|
+
"sh",
|
|
88
|
+
"-c",
|
|
89
|
+
"which k3s || curl -sfL https://get.k3s.io | sh -s - --write-kubeconfig-mode 644 --https-listen-port=16443",
|
|
90
|
+
],
|
|
91
|
+
"Installing k3s",
|
|
92
|
+
)
|
|
93
|
+
await self.run_in_vm(
|
|
94
|
+
[
|
|
95
|
+
"sh",
|
|
96
|
+
"-c",
|
|
97
|
+
"which helm || curl -sfL https://raw.githubusercontent.com/helm/helm/main/scripts/get-helm-3 | bash",
|
|
98
|
+
],
|
|
99
|
+
"Installing Helm",
|
|
100
|
+
)
|
|
101
|
+
|
|
102
|
+
async def deploy(
|
|
103
|
+
self,
|
|
104
|
+
set_values_list: list[str],
|
|
105
|
+
values_file: pathlib.Path | None = None,
|
|
106
|
+
import_images: list[str] | None = None,
|
|
107
|
+
pull_on_host: bool = False,
|
|
108
|
+
skip_pull: bool = False,
|
|
109
|
+
skip_restart_deployments: bool = False,
|
|
110
|
+
) -> None:
|
|
111
|
+
_ = await self.run_in_vm(
|
|
112
|
+
["sh", "-c", "mkdir -p /tmp/agentstack && cat >/tmp/agentstack/chart.tgz"],
|
|
113
|
+
"Preparing Helm chart",
|
|
114
|
+
input=(importlib.resources.files("agentstack_cli") / "data" / "helm-chart.tgz").read_bytes(),
|
|
115
|
+
)
|
|
116
|
+
values = {
|
|
117
|
+
**{svc: {"service": {"type": "LoadBalancer"}} for svc in ["collector", "docling", "ui", "phoenix"]},
|
|
118
|
+
"service": {"type": "LoadBalancer"},
|
|
119
|
+
"externalRegistries": {"public_github": str(Configuration().agent_registry)},
|
|
120
|
+
"encryptionKey": "Ovx8qImylfooq4-HNwOzKKDcXLZCB3c_m0JlB9eJBxc=",
|
|
121
|
+
"trustProxyHeaders": True,
|
|
122
|
+
"keycloak": {
|
|
123
|
+
"uiClientSecret": "agentstack-ui-secret",
|
|
124
|
+
"serverClientSecret": "agentstack-server-secret",
|
|
125
|
+
"service": {"type": "LoadBalancer"},
|
|
126
|
+
"auth": {"adminPassword": "admin"},
|
|
127
|
+
},
|
|
128
|
+
"features": {"uiLocalSetup": True},
|
|
129
|
+
"providerBuilds": {"enabled": True},
|
|
130
|
+
"localDockerRegistry": {"enabled": True},
|
|
131
|
+
"auth": {"enabled": False},
|
|
132
|
+
}
|
|
133
|
+
if values_file:
|
|
134
|
+
values = merge(values, yaml.safe_load(values_file.read_text()))
|
|
135
|
+
await self.run_in_vm(
|
|
136
|
+
["sh", "-c", "cat >/tmp/agentstack/values.yaml"],
|
|
137
|
+
"Preparing Helm values",
|
|
138
|
+
input=yaml.dump(values).encode("utf-8"),
|
|
139
|
+
)
|
|
140
|
+
|
|
141
|
+
images_str = (
|
|
142
|
+
await self.run_in_vm(
|
|
143
|
+
[
|
|
144
|
+
"/bin/bash",
|
|
145
|
+
"-c",
|
|
146
|
+
"helm template agentstack /tmp/agentstack/chart.tgz --values=/tmp/agentstack/values.yaml "
|
|
147
|
+
+ " ".join(shlex.quote(f"--set={value}") for value in set_values_list)
|
|
148
|
+
+ " | sed -n '/^\\s*image:/{ /{{/!{ s/.*image:\\s*//p } }'",
|
|
149
|
+
],
|
|
150
|
+
"Listing necessary images",
|
|
151
|
+
)
|
|
152
|
+
).stdout.decode()
|
|
153
|
+
|
|
154
|
+
def canonify(tag: str) -> str:
|
|
155
|
+
return tag if "." in tag.split("/")[0] else f"docker.io/{tag}"
|
|
156
|
+
|
|
157
|
+
required_images = {canonify(typing.cast(str, yaml.safe_load(line))) for line in images_str.splitlines()}
|
|
158
|
+
images_to_import = {canonify(tag) for tag in import_images or []}
|
|
159
|
+
images_to_pull = required_images - images_to_import
|
|
160
|
+
|
|
161
|
+
if not skip_pull:
|
|
162
|
+
if pull_on_host:
|
|
163
|
+
for image in images_to_pull:
|
|
164
|
+
await run_command(["docker", "pull", image], f"Pulling image {image} on host")
|
|
165
|
+
images_to_import = required_images
|
|
166
|
+
images_to_pull = set[str]()
|
|
167
|
+
|
|
168
|
+
if images_to_import:
|
|
169
|
+
await self.import_images(*images_to_import)
|
|
170
|
+
|
|
171
|
+
for image in images_to_pull:
|
|
172
|
+
async for attempt in AsyncRetrying(stop=stop_after_attempt(5)):
|
|
173
|
+
with attempt:
|
|
174
|
+
attempt_num = attempt.retry_state.attempt_number
|
|
175
|
+
await self.run_in_vm(
|
|
176
|
+
["k3s", "ctr", "image", "pull", image],
|
|
177
|
+
f"Pulling image {image}" + (f" (attempt {attempt_num})" if attempt_num > 1 else ""),
|
|
178
|
+
)
|
|
179
|
+
elif images_to_import:
|
|
180
|
+
await self.import_images(*images_to_import)
|
|
181
|
+
|
|
182
|
+
self.loaded_images = required_images
|
|
183
|
+
|
|
184
|
+
kubeconfig_path = anyio.Path(Configuration().lima_home) / self.vm_name / "copied-from-guest" / "kubeconfig.yaml"
|
|
185
|
+
await kubeconfig_path.parent.mkdir(parents=True, exist_ok=True)
|
|
186
|
+
await kubeconfig_path.write_text(
|
|
187
|
+
(
|
|
188
|
+
await self.run_in_vm(
|
|
189
|
+
["/bin/cat", "/etc/rancher/k3s/k3s.yaml"],
|
|
190
|
+
"Copying kubeconfig from Agent Stack platform",
|
|
191
|
+
)
|
|
192
|
+
).stdout.decode()
|
|
193
|
+
)
|
|
194
|
+
|
|
195
|
+
await self.run_in_vm(
|
|
196
|
+
[
|
|
197
|
+
"helm",
|
|
198
|
+
"upgrade",
|
|
199
|
+
"--install",
|
|
200
|
+
"agentstack",
|
|
201
|
+
"/tmp/agentstack/chart.tgz",
|
|
202
|
+
"--namespace=default",
|
|
203
|
+
"--create-namespace",
|
|
204
|
+
"--values=/tmp/agentstack/values.yaml",
|
|
205
|
+
"--timeout=20m",
|
|
206
|
+
"--wait",
|
|
207
|
+
"--kubeconfig=/etc/rancher/k3s/k3s.yaml",
|
|
208
|
+
*(f"--set={value}" for value in set_values_list),
|
|
209
|
+
],
|
|
210
|
+
"Deploying Agent Stack platform with Helm",
|
|
211
|
+
)
|
|
212
|
+
|
|
213
|
+
if import_images and not skip_restart_deployments:
|
|
214
|
+
await self.run_in_vm(
|
|
215
|
+
["k3s", "kubectl", "rollout", "restart", "deployment"],
|
|
216
|
+
"Restarting deployments to load imported images",
|
|
217
|
+
)
|