edge-containers-cli 3.0.4__tar.gz → 3.1.1__tar.gz
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.
- {edge-containers-cli-3.0.4 → edge-containers-cli-3.1.1}/.github/workflows/_release.yml +1 -1
- edge-containers-cli-3.1.1/.github/workflows/_sys_test.yml +36 -0
- {edge-containers-cli-3.0.4 → edge-containers-cli-3.1.1}/.github/workflows/ci.yml +13 -0
- {edge-containers-cli-3.0.4 → edge-containers-cli-3.1.1}/PKG-INFO +2 -3
- {edge-containers-cli-3.0.4 → edge-containers-cli-3.1.1}/pyproject.toml +1 -2
- {edge-containers-cli-3.0.4 → edge-containers-cli-3.1.1}/src/edge_containers_cli/_version.py +2 -2
- {edge-containers-cli-3.0.4 → edge-containers-cli-3.1.1}/src/edge_containers_cli/cmds/cli.py +6 -9
- {edge-containers-cli-3.0.4 → edge-containers-cli-3.1.1}/src/edge_containers_cli/cmds/helm.py +8 -5
- {edge-containers-cli-3.0.4 → edge-containers-cli-3.1.1}/src/edge_containers_cli/cmds/k8s_commands.py +64 -22
- edge-containers-cli-3.1.1/src/edge_containers_cli/cmds/kubectl.py +15 -0
- {edge-containers-cli-3.0.4 → edge-containers-cli-3.1.1}/src/edge_containers_cli/cmds/local_commands.py +48 -27
- {edge-containers-cli-3.0.4 → edge-containers-cli-3.1.1}/src/edge_containers_cli/docker.py +0 -80
- edge-containers-cli-3.1.1/src/edge_containers_cli/git.py +71 -0
- {edge-containers-cli-3.0.4 → edge-containers-cli-3.1.1}/src/edge_containers_cli/globals.py +10 -48
- {edge-containers-cli-3.0.4 → edge-containers-cli-3.1.1}/src/edge_containers_cli/utils.py +13 -0
- {edge-containers-cli-3.0.4 → edge-containers-cli-3.1.1}/src/edge_containers_cli.egg-info/PKG-INFO +2 -3
- {edge-containers-cli-3.0.4 → edge-containers-cli-3.1.1}/src/edge_containers_cli.egg-info/SOURCES.txt +1 -0
- {edge-containers-cli-3.0.4 → edge-containers-cli-3.1.1}/src/edge_containers_cli.egg-info/requires.txt +1 -2
- {edge-containers-cli-3.0.4 → edge-containers-cli-3.1.1}/tests/conftest.py +9 -3
- {edge-containers-cli-3.0.4 → edge-containers-cli-3.1.1}/tests/data/autocomplete.yaml +8 -3
- {edge-containers-cli-3.0.4 → edge-containers-cli-3.1.1}/tests/data/ioc.yaml +18 -5
- {edge-containers-cli-3.0.4 → edge-containers-cli-3.1.1}/tests/data/local.yaml +43 -5
- {edge-containers-cli-3.0.4 → edge-containers-cli-3.1.1}/tests/test_autocomplete.py +11 -9
- {edge-containers-cli-3.0.4 → edge-containers-cli-3.1.1}/tests/test_ioc.py +0 -3
- {edge-containers-cli-3.0.4 → edge-containers-cli-3.1.1}/tests/test_system.py +20 -14
- edge-containers-cli-3.0.4/src/edge_containers_cli/cmds/kubectl.py +0 -10
- edge-containers-cli-3.0.4/src/edge_containers_cli/git.py +0 -152
- {edge-containers-cli-3.0.4 → edge-containers-cli-3.1.1}/.copier-answers.yml +0 -0
- {edge-containers-cli-3.0.4 → edge-containers-cli-3.1.1}/.devcontainer/devcontainer.json +0 -0
- {edge-containers-cli-3.0.4 → edge-containers-cli-3.1.1}/.github/CONTRIBUTING.md +0 -0
- {edge-containers-cli-3.0.4 → edge-containers-cli-3.1.1}/.github/actions/install_requirements/action.yml +0 -0
- {edge-containers-cli-3.0.4 → edge-containers-cli-3.1.1}/.github/dependabot.yml +0 -0
- {edge-containers-cli-3.0.4 → edge-containers-cli-3.1.1}/.github/pages/index.html +0 -0
- {edge-containers-cli-3.0.4 → edge-containers-cli-3.1.1}/.github/pages/make_switcher.py +0 -0
- {edge-containers-cli-3.0.4 → edge-containers-cli-3.1.1}/.github/workflows/_check.yml +0 -0
- {edge-containers-cli-3.0.4 → edge-containers-cli-3.1.1}/.github/workflows/_dist.yml +0 -0
- {edge-containers-cli-3.0.4 → edge-containers-cli-3.1.1}/.github/workflows/_pypi.yml +0 -0
- {edge-containers-cli-3.0.4 → edge-containers-cli-3.1.1}/.github/workflows/_test.yml +0 -0
- {edge-containers-cli-3.0.4 → edge-containers-cli-3.1.1}/.github/workflows/_tox.yml +0 -0
- {edge-containers-cli-3.0.4 → edge-containers-cli-3.1.1}/.gitignore +0 -0
- {edge-containers-cli-3.0.4 → edge-containers-cli-3.1.1}/.pre-commit-config.yaml +0 -0
- {edge-containers-cli-3.0.4 → edge-containers-cli-3.1.1}/.vscode/extensions.json +0 -0
- {edge-containers-cli-3.0.4 → edge-containers-cli-3.1.1}/.vscode/launch.json +0 -0
- {edge-containers-cli-3.0.4 → edge-containers-cli-3.1.1}/.vscode/settings.json +0 -0
- {edge-containers-cli-3.0.4 → edge-containers-cli-3.1.1}/.vscode/tasks.json +0 -0
- {edge-containers-cli-3.0.4 → edge-containers-cli-3.1.1}/Dockerfile +0 -0
- {edge-containers-cli-3.0.4 → edge-containers-cli-3.1.1}/LICENSE +0 -0
- {edge-containers-cli-3.0.4 → edge-containers-cli-3.1.1}/README.md +0 -0
- {edge-containers-cli-3.0.4 → edge-containers-cli-3.1.1}/catalog-info.yaml +0 -0
- {edge-containers-cli-3.0.4 → edge-containers-cli-3.1.1}/docs/conf.py +0 -0
- {edge-containers-cli-3.0.4 → edge-containers-cli-3.1.1}/docs/developer/explanations/decisions/0001-record-architecture-decisions.rst +0 -0
- {edge-containers-cli-3.0.4 → edge-containers-cli-3.1.1}/docs/developer/explanations/decisions/0002-switched-to-pip-skeleton.rst +0 -0
- {edge-containers-cli-3.0.4 → edge-containers-cli-3.1.1}/docs/developer/explanations/decisions.rst +0 -0
- {edge-containers-cli-3.0.4 → edge-containers-cli-3.1.1}/docs/developer/how-to/build-docs.rst +0 -0
- {edge-containers-cli-3.0.4 → edge-containers-cli-3.1.1}/docs/developer/how-to/contribute.rst +0 -0
- {edge-containers-cli-3.0.4 → edge-containers-cli-3.1.1}/docs/developer/how-to/lint.rst +0 -0
- {edge-containers-cli-3.0.4 → edge-containers-cli-3.1.1}/docs/developer/how-to/make-release.rst +0 -0
- {edge-containers-cli-3.0.4 → edge-containers-cli-3.1.1}/docs/developer/how-to/pin-requirements.rst +0 -0
- {edge-containers-cli-3.0.4 → edge-containers-cli-3.1.1}/docs/developer/how-to/run-tests.rst +0 -0
- {edge-containers-cli-3.0.4 → edge-containers-cli-3.1.1}/docs/developer/how-to/static-analysis.rst +0 -0
- {edge-containers-cli-3.0.4 → edge-containers-cli-3.1.1}/docs/developer/how-to/test-container.rst +0 -0
- {edge-containers-cli-3.0.4 → edge-containers-cli-3.1.1}/docs/developer/how-to/update-tools.rst +0 -0
- {edge-containers-cli-3.0.4 → edge-containers-cli-3.1.1}/docs/developer/index.rst +0 -0
- {edge-containers-cli-3.0.4 → edge-containers-cli-3.1.1}/docs/developer/reference/standards.rst +0 -0
- {edge-containers-cli-3.0.4 → edge-containers-cli-3.1.1}/docs/developer/tutorials/dev-install.rst +0 -0
- {edge-containers-cli-3.0.4 → edge-containers-cli-3.1.1}/docs/genindex.rst +0 -0
- {edge-containers-cli-3.0.4 → edge-containers-cli-3.1.1}/docs/images/dls-favicon.ico +0 -0
- {edge-containers-cli-3.0.4 → edge-containers-cli-3.1.1}/docs/images/dls-logo.svg +0 -0
- {edge-containers-cli-3.0.4 → edge-containers-cli-3.1.1}/docs/index.rst +0 -0
- {edge-containers-cli-3.0.4 → edge-containers-cli-3.1.1}/docs/user/explanations/docs-structure.rst +0 -0
- {edge-containers-cli-3.0.4 → edge-containers-cli-3.1.1}/docs/user/how-to/run-container.rst +0 -0
- {edge-containers-cli-3.0.4 → edge-containers-cli-3.1.1}/docs/user/index.rst +0 -0
- {edge-containers-cli-3.0.4 → edge-containers-cli-3.1.1}/docs/user/reference/api.rst +0 -0
- {edge-containers-cli-3.0.4 → edge-containers-cli-3.1.1}/docs/user/tutorials/installation.rst +0 -0
- {edge-containers-cli-3.0.4 → edge-containers-cli-3.1.1}/setup.cfg +0 -0
- {edge-containers-cli-3.0.4 → edge-containers-cli-3.1.1}/src/edge_containers_cli/__init__.py +0 -0
- {edge-containers-cli-3.0.4 → edge-containers-cli-3.1.1}/src/edge_containers_cli/__main__.py +0 -0
- {edge-containers-cli-3.0.4 → edge-containers-cli-3.1.1}/src/edge_containers_cli/autocomplete.py +0 -0
- {edge-containers-cli-3.0.4 → edge-containers-cli-3.1.1}/src/edge_containers_cli/cmds/__init__.py +0 -0
- {edge-containers-cli-3.0.4 → edge-containers-cli-3.1.1}/src/edge_containers_cli/logging.py +0 -0
- {edge-containers-cli-3.0.4 → edge-containers-cli-3.1.1}/src/edge_containers_cli/shell.py +0 -0
- {edge-containers-cli-3.0.4 → edge-containers-cli-3.1.1}/src/edge_containers_cli.egg-info/dependency_links.txt +0 -0
- {edge-containers-cli-3.0.4 → edge-containers-cli-3.1.1}/src/edge_containers_cli.egg-info/entry_points.txt +0 -0
- {edge-containers-cli-3.0.4 → edge-containers-cli-3.1.1}/src/edge_containers_cli.egg-info/top_level.txt +0 -0
- {edge-containers-cli-3.0.4 → edge-containers-cli-3.1.1}/tests/__init__.py +0 -0
- {edge-containers-cli-3.0.4 → edge-containers-cli-3.1.1}/tests/data/example-ibek-config/ioc.db +0 -0
- {edge-containers-cli-3.0.4 → edge-containers-cli-3.1.1}/tests/data/example-ibek-config/ioc.yaml +0 -0
- {edge-containers-cli-3.0.4 → edge-containers-cli-3.1.1}/tests/data/services/bl45p-ea-ioc-01/config/ioc.yaml +0 -0
- {edge-containers-cli-3.0.4 → edge-containers-cli-3.1.1}/tests/data/services/bl45p-ea-ioc-01/pretend_helm.tgz +0 -0
- {edge-containers-cli-3.0.4 → edge-containers-cli-3.1.1}/tests/data/services/bl45p-ea-ioc-01/values.yaml +0 -0
- {edge-containers-cli-3.0.4 → edge-containers-cli-3.1.1}/tests/test_cli.py +0 -0
- {edge-containers-cli-3.0.4 → edge-containers-cli-3.1.1}/tests/test_local.py +0 -0
|
@@ -23,7 +23,7 @@ jobs:
|
|
|
23
23
|
- name: Create GitHub Release
|
|
24
24
|
# We pin to the SHA, not the tag, for security reasons.
|
|
25
25
|
# https://docs.github.com/en/actions/learn-github-actions/security-hardening-for-github-actions#using-third-party-actions
|
|
26
|
-
uses: softprops/action-gh-release@
|
|
26
|
+
uses: softprops/action-gh-release@9d7c94cfd0a1f3ed45544c887983e9fa900f0564 # v0.1.15
|
|
27
27
|
with:
|
|
28
28
|
prerelease: ${{ contains(github.ref_name, 'a') || contains(github.ref_name, 'b') || contains(github.ref_name, 'rc') }}
|
|
29
29
|
files: "*"
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
on:
|
|
2
|
+
workflow_call:
|
|
3
|
+
inputs:
|
|
4
|
+
python-version:
|
|
5
|
+
type: string
|
|
6
|
+
description: The version of python to install
|
|
7
|
+
required: true
|
|
8
|
+
runs-on:
|
|
9
|
+
type: string
|
|
10
|
+
description: The runner to run this job on
|
|
11
|
+
required: true
|
|
12
|
+
|
|
13
|
+
jobs:
|
|
14
|
+
run:
|
|
15
|
+
runs-on: ${{ inputs.runs-on }}
|
|
16
|
+
env:
|
|
17
|
+
EC_INTERACTIVE_TESTING: "true"
|
|
18
|
+
EC_K8S_NAMESPACE: "default"
|
|
19
|
+
EC_SERVICES_REPO: "https://github.com/marcelldls/bl01t.git"
|
|
20
|
+
steps:
|
|
21
|
+
- name: start minikube
|
|
22
|
+
id: minikube
|
|
23
|
+
uses: medyagh/setup-minikube@master
|
|
24
|
+
- run: kubectl version
|
|
25
|
+
- run: helm version
|
|
26
|
+
- name: Checkout
|
|
27
|
+
uses: actions/checkout@v4
|
|
28
|
+
- name: Install latest versions of python packages
|
|
29
|
+
uses: ./.github/actions/install_requirements
|
|
30
|
+
with:
|
|
31
|
+
python-version: ${{ inputs.python-version }}
|
|
32
|
+
pip-install: ".[dev]"
|
|
33
|
+
- name: Set up namespace
|
|
34
|
+
run: ec deploy epics-pvcs 2024.2.1
|
|
35
|
+
- name: system tests
|
|
36
|
+
run: tox -e tests
|
|
@@ -34,6 +34,19 @@ jobs:
|
|
|
34
34
|
secrets:
|
|
35
35
|
CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }}
|
|
36
36
|
|
|
37
|
+
system:
|
|
38
|
+
needs: check
|
|
39
|
+
if: needs.check.outputs.branch-pr == ''
|
|
40
|
+
strategy:
|
|
41
|
+
matrix:
|
|
42
|
+
runs-on: ["ubuntu-latest"]
|
|
43
|
+
python-version: ["3.11"]
|
|
44
|
+
fail-fast: false
|
|
45
|
+
uses: ./.github/workflows/_sys_test.yml
|
|
46
|
+
with:
|
|
47
|
+
runs-on: ${{ matrix.runs-on }}
|
|
48
|
+
python-version: ${{ matrix.python-version }}
|
|
49
|
+
|
|
37
50
|
dist:
|
|
38
51
|
needs: check
|
|
39
52
|
if: needs.check.outputs.branch-pr == ''
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: edge-containers-cli
|
|
3
|
-
Version: 3.
|
|
3
|
+
Version: 3.1.1
|
|
4
4
|
Summary: CLI for deploying and managing epics containers IOCs and services
|
|
5
5
|
Author-email: Giles Knap <giles.knap@gmail.com>
|
|
6
6
|
License: Apache License
|
|
@@ -219,8 +219,7 @@ Requires-Dist: typer[all]
|
|
|
219
219
|
Requires-Dist: requests
|
|
220
220
|
Requires-Dist: ruamel.yaml
|
|
221
221
|
Requires-Dist: jinja2
|
|
222
|
-
Requires-Dist:
|
|
223
|
-
Requires-Dist: pyarrow
|
|
222
|
+
Requires-Dist: polars
|
|
224
223
|
Provides-Extra: dev
|
|
225
224
|
Requires-Dist: copier; extra == "dev"
|
|
226
225
|
Requires-Dist: pipdeptree; extra == "dev"
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import tempfile
|
|
2
2
|
from pathlib import Path
|
|
3
3
|
|
|
4
|
+
import polars
|
|
4
5
|
import typer
|
|
5
6
|
from natsort import natsorted
|
|
6
7
|
|
|
@@ -159,18 +160,14 @@ def list(
|
|
|
159
160
|
ctx: typer.Context,
|
|
160
161
|
):
|
|
161
162
|
"""List all IOCs/services available in the helm registry"""
|
|
162
|
-
typer.echo(typer.style(f"{'Available services:':35}Latest instance:", bold=True))
|
|
163
163
|
tmp_dir = Path(tempfile.mkdtemp())
|
|
164
164
|
svc_graph = create_svc_graph(ctx.obj.beamline_repo, tmp_dir)
|
|
165
165
|
svc_list = natsorted(svc_graph.keys())
|
|
166
166
|
log.debug(f"svc_graph = {svc_graph}")
|
|
167
167
|
|
|
168
|
-
for svc in svc_list
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
else:
|
|
172
|
-
latest_instance = natsorted(svc_graph[svc])[-1]
|
|
173
|
-
typer.echo(f"{svc:35}{latest_instance}")
|
|
168
|
+
versions = [natsorted(svc_graph[svc])[-1] for svc in svc_list]
|
|
169
|
+
services_df = polars.from_dict({"name": svc_list, "version": versions})
|
|
170
|
+
print(services_df)
|
|
174
171
|
|
|
175
172
|
cleanup_temp(tmp_dir)
|
|
176
173
|
|
|
@@ -183,7 +180,6 @@ def instances(
|
|
|
183
180
|
),
|
|
184
181
|
):
|
|
185
182
|
"""List all versions of the IOC/service available in the helm registry"""
|
|
186
|
-
typer.echo(f"Available instances for {service_name}:")
|
|
187
183
|
tmp_dir = Path(tempfile.mkdtemp())
|
|
188
184
|
svc_graph = create_svc_graph(ctx.obj.beamline_repo, tmp_dir)
|
|
189
185
|
try:
|
|
@@ -192,7 +188,8 @@ def instances(
|
|
|
192
188
|
svc_list = []
|
|
193
189
|
|
|
194
190
|
sorted_list = natsorted(svc_list)[::-1]
|
|
195
|
-
|
|
191
|
+
services_df = polars.from_dict({"version": sorted_list})
|
|
192
|
+
print(services_df)
|
|
196
193
|
|
|
197
194
|
cleanup_temp(tmp_dir)
|
|
198
195
|
|
{edge-containers-cli-3.0.4 → edge-containers-cli-3.1.1}/src/edge_containers_cli/cmds/helm.py
RENAMED
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import tempfile
|
|
2
|
-
from datetime import datetime
|
|
3
2
|
from pathlib import Path
|
|
4
3
|
from typing import Optional
|
|
5
4
|
|
|
@@ -7,7 +6,13 @@ import typer
|
|
|
7
6
|
|
|
8
7
|
import edge_containers_cli.globals as globals
|
|
9
8
|
import edge_containers_cli.shell as shell
|
|
10
|
-
from edge_containers_cli.utils import
|
|
9
|
+
from edge_containers_cli.utils import (
|
|
10
|
+
chdir,
|
|
11
|
+
check_instance_path,
|
|
12
|
+
cleanup_temp,
|
|
13
|
+
local_version,
|
|
14
|
+
log,
|
|
15
|
+
)
|
|
11
16
|
|
|
12
17
|
|
|
13
18
|
class Helm:
|
|
@@ -31,9 +36,7 @@ class Helm:
|
|
|
31
36
|
self.beamline_repo = repo
|
|
32
37
|
self.namespace = namespace
|
|
33
38
|
self.args = args
|
|
34
|
-
self.version = version or
|
|
35
|
-
datetime.now(), "%Y.%-m.%-d-b%-H.%-M"
|
|
36
|
-
)
|
|
39
|
+
self.version = version or local_version()
|
|
37
40
|
self.template = template
|
|
38
41
|
|
|
39
42
|
self.tmp = Path(tempfile.mkdtemp())
|
{edge-containers-cli-3.0.4 → edge-containers-cli-3.1.1}/src/edge_containers_cli/cmds/k8s_commands.py
RENAMED
|
@@ -10,13 +10,13 @@ from io import StringIO
|
|
|
10
10
|
from pathlib import Path
|
|
11
11
|
from typing import Optional
|
|
12
12
|
|
|
13
|
-
import
|
|
13
|
+
import polars
|
|
14
14
|
import typer
|
|
15
15
|
|
|
16
16
|
import edge_containers_cli.globals as globals
|
|
17
17
|
import edge_containers_cli.shell as shell
|
|
18
18
|
from edge_containers_cli.cmds.helm import Helm
|
|
19
|
-
from edge_containers_cli.cmds.kubectl import
|
|
19
|
+
from edge_containers_cli.cmds.kubectl import jsonpath_deploy_info, jsonpath_pod_info
|
|
20
20
|
from edge_containers_cli.logging import log
|
|
21
21
|
|
|
22
22
|
|
|
@@ -72,7 +72,6 @@ class K8sCommands:
|
|
|
72
72
|
):
|
|
73
73
|
self.namespace: str = ""
|
|
74
74
|
self.beamline_repo: str = ""
|
|
75
|
-
self.service_type: str = ""
|
|
76
75
|
# TODO isnt ctx always set??
|
|
77
76
|
if ctx is not None:
|
|
78
77
|
namespace = ctx.namespace
|
|
@@ -170,27 +169,70 @@ class K8sCommands:
|
|
|
170
169
|
def ps(self, all: bool, wide: bool):
|
|
171
170
|
"""List all IOCs and Services in the current namespace"""
|
|
172
171
|
|
|
173
|
-
|
|
174
|
-
f"helm list -n {self.namespace} -o json", interactive=False
|
|
175
|
-
)
|
|
176
|
-
df = pd.read_json(StringIO(str(helm_json)))
|
|
177
|
-
log.debug(df)
|
|
172
|
+
services_df = polars.DataFrame()
|
|
178
173
|
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
f"kubectl get
|
|
174
|
+
# Gives all services (running & not running) and their image
|
|
175
|
+
for resource in ["deployment", "statefulset"]:
|
|
176
|
+
kubectl_res = shell.run_command(
|
|
177
|
+
f"kubectl get {resource} -n {self.namespace} {jsonpath_deploy_info}",
|
|
183
178
|
interactive=False,
|
|
184
179
|
)
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
180
|
+
if kubectl_res:
|
|
181
|
+
res_df = polars.read_csv(
|
|
182
|
+
StringIO(str(kubectl_res)),
|
|
183
|
+
separator=",",
|
|
184
|
+
has_header=False,
|
|
185
|
+
new_columns=["name", "image"],
|
|
186
|
+
)
|
|
187
|
+
log.debug(res_df)
|
|
188
|
+
services_df = polars.concat([services_df, res_df], how="diagonal")
|
|
189
|
+
if services_df.is_empty():
|
|
190
|
+
print("No deployed services found")
|
|
191
|
+
raise typer.Exit()
|
|
192
|
+
|
|
193
|
+
# Gives the status, restarts for running services
|
|
194
|
+
kubectl_gtpo = shell.run_command(
|
|
195
|
+
f"kubectl get pods -n {self.namespace} {jsonpath_pod_info}",
|
|
196
|
+
interactive=False,
|
|
197
|
+
)
|
|
198
|
+
if kubectl_gtpo:
|
|
199
|
+
gtpo_df = polars.read_csv(
|
|
200
|
+
StringIO(str(kubectl_gtpo)),
|
|
201
|
+
separator=",",
|
|
202
|
+
has_header=False,
|
|
203
|
+
new_columns=["name", "running", "restarts"],
|
|
189
204
|
)
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
205
|
+
services_df = services_df.join(gtpo_df, on="name", how="left")
|
|
206
|
+
services_df = services_df.with_columns(
|
|
207
|
+
polars.col("running").replace({"Running": True}, default=False),
|
|
208
|
+
polars.col("restarts").fill_null(0),
|
|
209
|
+
)
|
|
210
|
+
elif all:
|
|
211
|
+
services_df = services_df.with_columns(
|
|
212
|
+
running=polars.lit(False), restarts=polars.lit(0)
|
|
213
|
+
)
|
|
214
|
+
else:
|
|
215
|
+
print("No running services found")
|
|
216
|
+
raise typer.Exit()
|
|
195
217
|
|
|
196
|
-
|
|
218
|
+
# Adds the version, deployment time for all services
|
|
219
|
+
helm_out = shell.run_command(
|
|
220
|
+
f"helm list -n {self.namespace} -o json", interactive=False
|
|
221
|
+
)
|
|
222
|
+
helm_df = polars.read_json(StringIO(str(helm_out)))
|
|
223
|
+
helm_df = helm_df.rename({"app_version": "version", "updated": "deployed"})
|
|
224
|
+
helm_df = helm_df.with_columns(polars.col("deployed").str.slice(0, 19))
|
|
225
|
+
services_df = services_df.join(helm_df, on="name", how="left")
|
|
226
|
+
log.debug(services_df)
|
|
227
|
+
|
|
228
|
+
# Arrange columns
|
|
229
|
+
services_df = services_df.select(
|
|
230
|
+
["name", "version", "running", "restarts", "deployed", "image"]
|
|
231
|
+
)
|
|
232
|
+
if not all:
|
|
233
|
+
services_df = services_df.filter(polars.col("running").eq(True))
|
|
234
|
+
log.debug(services_df)
|
|
235
|
+
if not wide:
|
|
236
|
+
services_df.drop_in_place("image")
|
|
237
|
+
log.debug(services_df)
|
|
238
|
+
print(services_df)
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
jsonpath_pod_info = (
|
|
2
|
+
"-o jsonpath='"
|
|
3
|
+
r'{range .items[*]}{..labels.app}{","}{.status.phase}'
|
|
4
|
+
r'{","}{..containerStatuses[0].restartCount}'
|
|
5
|
+
r'{"\n"}{end}'
|
|
6
|
+
"'"
|
|
7
|
+
)
|
|
8
|
+
|
|
9
|
+
jsonpath_deploy_info = (
|
|
10
|
+
"-o jsonpath='"
|
|
11
|
+
r'{range .items[*]}{.metadata.name}{","}'
|
|
12
|
+
r"{range .spec.template.spec.containers[*]}{.image}"
|
|
13
|
+
r'{"\n"}{end}{end}'
|
|
14
|
+
"'"
|
|
15
|
+
)
|
|
@@ -9,6 +9,7 @@ However, for the moment, Using this by connecting to each server and running
|
|
|
9
9
|
tool like Portainer is a decent workflow.
|
|
10
10
|
"""
|
|
11
11
|
|
|
12
|
+
import json
|
|
12
13
|
import re
|
|
13
14
|
import tempfile
|
|
14
15
|
from datetime import datetime
|
|
@@ -16,7 +17,7 @@ from io import StringIO
|
|
|
16
17
|
from pathlib import Path
|
|
17
18
|
from typing import Optional
|
|
18
19
|
|
|
19
|
-
import
|
|
20
|
+
import polars
|
|
20
21
|
import requests
|
|
21
22
|
import typer
|
|
22
23
|
|
|
@@ -31,6 +32,7 @@ from edge_containers_cli.utils import (
|
|
|
31
32
|
cleanup_temp,
|
|
32
33
|
generic_ioc_from_image,
|
|
33
34
|
get_instance_image_name,
|
|
35
|
+
local_version,
|
|
34
36
|
)
|
|
35
37
|
|
|
36
38
|
|
|
@@ -73,7 +75,7 @@ class LocalCommands:
|
|
|
73
75
|
self.docker.remove(self.service_name)
|
|
74
76
|
|
|
75
77
|
def _do_deploy(self, ioc_instance: Path, version: str, args: str):
|
|
76
|
-
service_name,
|
|
78
|
+
service_name, _ = check_instance_path(ioc_instance)
|
|
77
79
|
|
|
78
80
|
image = get_instance_image_name(ioc_instance)
|
|
79
81
|
log.debug(f"deploying {ioc_instance} with image {image}")
|
|
@@ -120,7 +122,7 @@ class LocalCommands:
|
|
|
120
122
|
Use a local copy of an ioc instance definition to deploy a temporary
|
|
121
123
|
version of the IOC to the local docker instance
|
|
122
124
|
"""
|
|
123
|
-
version =
|
|
125
|
+
version = local_version()
|
|
124
126
|
if not yes:
|
|
125
127
|
typer.echo(
|
|
126
128
|
f"Deploy TEMPORARY version {version} "
|
|
@@ -163,35 +165,54 @@ class LocalCommands:
|
|
|
163
165
|
def ps(self, all: bool, wide: bool):
|
|
164
166
|
all_arg = " --all" if all else ""
|
|
165
167
|
|
|
166
|
-
#
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
result = shell.run_command(
|
|
171
|
-
f"{self.docker.docker} ps{all_arg} --filter label=is_IOC=true "
|
|
172
|
-
f'--format "{format}"',
|
|
168
|
+
# List services
|
|
169
|
+
avail_services = shell.run_command(
|
|
170
|
+
f"{self.docker.docker} ps{all_arg} -q --filter label=is_IOC=true",
|
|
173
171
|
interactive=False,
|
|
174
172
|
)
|
|
175
173
|
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
174
|
+
if not avail_services:
|
|
175
|
+
if all_arg:
|
|
176
|
+
print("No deployed services found")
|
|
177
|
+
else:
|
|
178
|
+
print("No running services found")
|
|
179
|
+
raise typer.Exit()
|
|
180
|
+
|
|
181
|
+
# Retrieve data
|
|
182
|
+
result_json = shell.run_command(
|
|
183
|
+
f"{self.docker.docker} inspect "
|
|
184
|
+
f"$({self.docker.docker} ps{all_arg} -q --filter label=is_IOC=true)",
|
|
185
|
+
interactive=False,
|
|
188
186
|
)
|
|
189
|
-
log.debug(
|
|
187
|
+
log.debug(result_json)
|
|
188
|
+
services_dicts = json.load(StringIO(str(result_json)))
|
|
189
|
+
|
|
190
|
+
select_data = []
|
|
191
|
+
for service in services_dicts:
|
|
192
|
+
# Make docker output look like podman
|
|
193
|
+
if self.docker.is_docker:
|
|
194
|
+
service["Name"] = service["Name"][1:] # inspect leads name with /
|
|
195
|
+
|
|
196
|
+
# Note if adding more keys that there are differences
|
|
197
|
+
# between what is available between docker and podman
|
|
198
|
+
select_data.append(
|
|
199
|
+
{
|
|
200
|
+
"name": service["Name"],
|
|
201
|
+
"version": service["Config"]["Labels"]["version"],
|
|
202
|
+
"running": "true" if service["State"]["Running"] else "false",
|
|
203
|
+
"restarts": service["RestartCount"],
|
|
204
|
+
"deployed": datetime.strptime(
|
|
205
|
+
service["Created"].split(".")[0], "%Y-%m-%dT%H:%M:%S"
|
|
206
|
+
),
|
|
207
|
+
"image": service["Config"]["Image"],
|
|
208
|
+
}
|
|
209
|
+
)
|
|
210
|
+
log.debug(select_data)
|
|
190
211
|
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
212
|
+
services_df = polars.DataFrame(select_data)
|
|
213
|
+
if not wide:
|
|
214
|
+
services_df.drop_in_place("image")
|
|
215
|
+
print(services_df)
|
|
195
216
|
|
|
196
217
|
def validate_instance(self, ioc_instance: Path):
|
|
197
218
|
check_instance_path(ioc_instance)
|
|
@@ -3,10 +3,8 @@ Utility functions for working interacting with docker / podman CLI
|
|
|
3
3
|
"""
|
|
4
4
|
|
|
5
5
|
import re
|
|
6
|
-
import sys
|
|
7
6
|
from pathlib import Path
|
|
8
7
|
from time import sleep
|
|
9
|
-
from typing import Optional
|
|
10
8
|
|
|
11
9
|
import typer
|
|
12
10
|
|
|
@@ -14,12 +12,6 @@ import edge_containers_cli.globals as globals
|
|
|
14
12
|
import edge_containers_cli.shell as shell
|
|
15
13
|
from edge_containers_cli.logging import log
|
|
16
14
|
|
|
17
|
-
IMAGE_TAG = "local"
|
|
18
|
-
MOUNTED_FILES = ["/.bashrc", "/.inputrc", "/.bash_eternal_history"]
|
|
19
|
-
|
|
20
|
-
# podman needs this security option to allow containers to mount tmp etc.
|
|
21
|
-
PODMAN_OPT = " --security-opt=label=type:container_runtime_t"
|
|
22
|
-
|
|
23
15
|
|
|
24
16
|
class Docker:
|
|
25
17
|
"""
|
|
@@ -67,78 +59,6 @@ class Docker:
|
|
|
67
59
|
|
|
68
60
|
log.debug(f"buildx={self.is_buildx} ({result})")
|
|
69
61
|
|
|
70
|
-
def _all_params(
|
|
71
|
-
self, args: str, mounts: Optional[list[Path]] = None, exec: bool = False
|
|
72
|
-
):
|
|
73
|
-
"""
|
|
74
|
-
set up parameters for call to docker/podman
|
|
75
|
-
"""
|
|
76
|
-
opts = PODMAN_OPT if not self.is_docker and not exec else ""
|
|
77
|
-
|
|
78
|
-
if self.devcontainer:
|
|
79
|
-
if sys.stdin.isatty():
|
|
80
|
-
# interactive
|
|
81
|
-
env = "-e DISPLAY -e SHELL -e TERM -it"
|
|
82
|
-
else:
|
|
83
|
-
env = "-e DISPLAY -e SHELL"
|
|
84
|
-
|
|
85
|
-
volumes = ""
|
|
86
|
-
for file in MOUNTED_FILES:
|
|
87
|
-
file_path = Path(file)
|
|
88
|
-
if file_path.exists():
|
|
89
|
-
volumes += f" -v {file}:/root/{file_path.name}"
|
|
90
|
-
if mounts is not None:
|
|
91
|
-
for mount in mounts:
|
|
92
|
-
volumes += f" -v {mount}"
|
|
93
|
-
|
|
94
|
-
log.debug(f"env={env} volumes={volumes} opts={opts}")
|
|
95
|
-
|
|
96
|
-
params = f"{env}{opts}{volumes}" + f" {args}" if args else ""
|
|
97
|
-
else:
|
|
98
|
-
params = f"{opts}" + (f"{args}" if args else "")
|
|
99
|
-
|
|
100
|
-
return params
|
|
101
|
-
|
|
102
|
-
def run(self, name: str, args: str = "", mounts: Optional[list[Path]] = None):
|
|
103
|
-
"""
|
|
104
|
-
run a command in a local container
|
|
105
|
-
"""
|
|
106
|
-
params = self._all_params(args, mounts=mounts)
|
|
107
|
-
shell.run_command(
|
|
108
|
-
f"{self.docker} run --rm --name {name} {params}", interactive=True
|
|
109
|
-
)
|
|
110
|
-
|
|
111
|
-
def build(
|
|
112
|
-
self,
|
|
113
|
-
context: str,
|
|
114
|
-
name: str,
|
|
115
|
-
target: str,
|
|
116
|
-
args: str = "",
|
|
117
|
-
cache_from: str = "",
|
|
118
|
-
cache_to: str = "",
|
|
119
|
-
push: bool = False,
|
|
120
|
-
arch: globals.Architecture = globals.Architecture.linux,
|
|
121
|
-
):
|
|
122
|
-
"""
|
|
123
|
-
build a container
|
|
124
|
-
"""
|
|
125
|
-
if self.is_buildx:
|
|
126
|
-
cmd = f"{self.docker} buildx"
|
|
127
|
-
shell.run_command(
|
|
128
|
-
f"{cmd} create --driver docker-container --use", interactive=False
|
|
129
|
-
)
|
|
130
|
-
args += f" --cache-from={cache_from}" if cache_from else ""
|
|
131
|
-
args += f" --cache-to={cache_to},mode=max" if cache_to else ""
|
|
132
|
-
args += " --push" if push else " --load "
|
|
133
|
-
else:
|
|
134
|
-
cmd = f"{self.docker}"
|
|
135
|
-
|
|
136
|
-
t_arch = f" --build-arg TARGET_ARCHITECTURE={arch}" if self.devcontainer else ""
|
|
137
|
-
|
|
138
|
-
shell.run_command(
|
|
139
|
-
f"{cmd} build --target {target}{t_arch} {args} -t {name} {context}"
|
|
140
|
-
)
|
|
141
|
-
|
|
142
62
|
def exec(
|
|
143
63
|
self,
|
|
144
64
|
container: str,
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Utility functions for working with git
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
import os
|
|
6
|
+
from pathlib import Path
|
|
7
|
+
|
|
8
|
+
import edge_containers_cli.shell as shell
|
|
9
|
+
from edge_containers_cli.logging import log
|
|
10
|
+
from edge_containers_cli.shell import check_services_repo
|
|
11
|
+
from edge_containers_cli.utils import chdir
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
def create_svc_graph(repo: str, folder: Path) -> dict:
|
|
15
|
+
"""
|
|
16
|
+
return a dictionary of the available IOCs (by discovering the children
|
|
17
|
+
to the services/ folder in the beamline repo) as well as a list of the corresponding
|
|
18
|
+
available versions for each IOC (by discovering the tags in the beamline repo at
|
|
19
|
+
which changes to the instance were made since the last tag) and the respective
|
|
20
|
+
list of available versions
|
|
21
|
+
"""
|
|
22
|
+
svc_graph = {}
|
|
23
|
+
|
|
24
|
+
check_services_repo(repo)
|
|
25
|
+
shell.run_command(f"git clone {repo} {folder}", interactive=False)
|
|
26
|
+
path_list = os.listdir(os.path.join(folder, "services"))
|
|
27
|
+
service_list = [
|
|
28
|
+
path
|
|
29
|
+
for path in path_list
|
|
30
|
+
if os.path.isdir(os.path.join(folder, "services", path))
|
|
31
|
+
]
|
|
32
|
+
log.debug(f"service_list = {service_list}")
|
|
33
|
+
|
|
34
|
+
with chdir(folder): # From python 3.11 can use contextlib.chdir(folder)
|
|
35
|
+
for service_name in service_list:
|
|
36
|
+
service_name = Path(service_name).name
|
|
37
|
+
result = str(
|
|
38
|
+
shell.run_command("git tag --sort=committerdate", interactive=False)
|
|
39
|
+
)
|
|
40
|
+
log.debug(f"checking these tags for changes in the instance: {result}")
|
|
41
|
+
|
|
42
|
+
version_list = []
|
|
43
|
+
tags = result.split("\n")
|
|
44
|
+
tags.remove("")
|
|
45
|
+
|
|
46
|
+
for tag_no, _ in enumerate(tags):
|
|
47
|
+
# Check initial configuration
|
|
48
|
+
if not tag_no:
|
|
49
|
+
cmd = f"git ls-tree -r {tags[tag_no]} --name-only"
|
|
50
|
+
result = str(
|
|
51
|
+
shell.run_command(cmd, interactive=False, error_OK=True)
|
|
52
|
+
)
|
|
53
|
+
if service_name in result:
|
|
54
|
+
version_list.append(tags[tag_no])
|
|
55
|
+
|
|
56
|
+
# Check repo changes
|
|
57
|
+
else:
|
|
58
|
+
cmd = f"git diff --name-only {tags[tag_no-1]} {tags[tag_no]}"
|
|
59
|
+
result = str(
|
|
60
|
+
shell.run_command(cmd, interactive=False, error_OK=True)
|
|
61
|
+
)
|
|
62
|
+
if service_name in result:
|
|
63
|
+
version_list.append(tags[tag_no])
|
|
64
|
+
|
|
65
|
+
# Capture services committed since the most recent tag
|
|
66
|
+
if not version_list:
|
|
67
|
+
version_list.append("")
|
|
68
|
+
|
|
69
|
+
svc_graph[service_name] = version_list
|
|
70
|
+
|
|
71
|
+
return svc_graph
|