mrok 0.2.3__tar.gz → 0.3.0__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.
- {mrok-0.2.3 → mrok-0.3.0}/PKG-INFO +1 -1
- {mrok-0.2.3 → mrok-0.3.0}/mrok/cli/commands/admin/list/instances.py +24 -4
- {mrok-0.2.3 → mrok-0.3.0}/mrok/cli/commands/admin/register/extensions.py +2 -2
- {mrok-0.2.3 → mrok-0.3.0}/mrok/cli/commands/admin/register/instances.py +3 -3
- {mrok-0.2.3 → mrok-0.3.0}/mrok/cli/commands/admin/unregister/extensions.py +2 -2
- {mrok-0.2.3 → mrok-0.3.0}/mrok/cli/commands/admin/unregister/instances.py +2 -2
- {mrok-0.2.3 → mrok-0.3.0}/mrok/controller/routes/extensions.py +9 -7
- {mrok-0.2.3 → mrok-0.3.0}/mrok/ziti/identities.py +50 -20
- {mrok-0.2.3 → mrok-0.3.0}/mrok/ziti/services.py +8 -8
- {mrok-0.2.3 → mrok-0.3.0}/pyproject.toml +1 -1
- {mrok-0.2.3 → mrok-0.3.0}/settings.yaml +2 -2
- {mrok-0.2.3 → mrok-0.3.0}/tests/cli/admin/test_list.py +36 -15
- {mrok-0.2.3 → mrok-0.3.0}/tests/cli/admin/test_register.py +8 -3
- {mrok-0.2.3 → mrok-0.3.0}/tests/cli/admin/test_unregister.py +3 -2
- {mrok-0.2.3 → mrok-0.3.0}/tests/controller/test_extensions.py +13 -12
- {mrok-0.2.3 → mrok-0.3.0}/tests/ziti/test_identities.py +163 -37
- {mrok-0.2.3 → mrok-0.3.0}/tests/ziti/test_services.py +16 -16
- {mrok-0.2.3 → mrok-0.3.0}/.github/actions/setup-python-env/action.yml +0 -0
- {mrok-0.2.3 → mrok-0.3.0}/.github/workflows/assets/turing_team_pr_bot.png +0 -0
- {mrok-0.2.3 → mrok-0.3.0}/.github/workflows/notify-pr-closed.yaml +0 -0
- {mrok-0.2.3 → mrok-0.3.0}/.github/workflows/notify-pr-reviewed.yml +0 -0
- {mrok-0.2.3 → mrok-0.3.0}/.github/workflows/pr-build-merge.yaml +0 -0
- {mrok-0.2.3 → mrok-0.3.0}/.github/workflows/release.yml +0 -0
- {mrok-0.2.3 → mrok-0.3.0}/.gitignore +0 -0
- {mrok-0.2.3 → mrok-0.3.0}/.pre-commit-config.yaml +0 -0
- {mrok-0.2.3 → mrok-0.3.0}/.python-version +0 -0
- {mrok-0.2.3 → mrok-0.3.0}/LICENSE.txt +0 -0
- {mrok-0.2.3 → mrok-0.3.0}/README.md +0 -0
- {mrok-0.2.3 → mrok-0.3.0}/dev.Dockerfile +0 -0
- {mrok-0.2.3 → mrok-0.3.0}/docker-compose.yaml +0 -0
- {mrok-0.2.3 → mrok-0.3.0}/entrypoint.sh +0 -0
- {mrok-0.2.3 → mrok-0.3.0}/mrok/__init__.py +0 -0
- {mrok-0.2.3 → mrok-0.3.0}/mrok/agent/__init__.py +0 -0
- {mrok-0.2.3 → mrok-0.3.0}/mrok/agent/sidecar/__init__.py +0 -0
- {mrok-0.2.3 → mrok-0.3.0}/mrok/agent/sidecar/app.py +0 -0
- {mrok-0.2.3 → mrok-0.3.0}/mrok/agent/sidecar/main.py +0 -0
- {mrok-0.2.3 → mrok-0.3.0}/mrok/agent/ziticorn.py +0 -0
- {mrok-0.2.3 → mrok-0.3.0}/mrok/cli/__init__.py +0 -0
- {mrok-0.2.3 → mrok-0.3.0}/mrok/cli/commands/__init__.py +0 -0
- {mrok-0.2.3 → mrok-0.3.0}/mrok/cli/commands/admin/__init__.py +0 -0
- {mrok-0.2.3 → mrok-0.3.0}/mrok/cli/commands/admin/bootstrap.py +0 -0
- {mrok-0.2.3 → mrok-0.3.0}/mrok/cli/commands/admin/list/__init__.py +0 -0
- {mrok-0.2.3 → mrok-0.3.0}/mrok/cli/commands/admin/list/extensions.py +0 -0
- {mrok-0.2.3 → mrok-0.3.0}/mrok/cli/commands/admin/register/__init__.py +0 -0
- {mrok-0.2.3 → mrok-0.3.0}/mrok/cli/commands/admin/unregister/__init__.py +0 -0
- {mrok-0.2.3 → mrok-0.3.0}/mrok/cli/commands/admin/utils.py +0 -0
- {mrok-0.2.3 → mrok-0.3.0}/mrok/cli/commands/agent/__init__.py +0 -0
- {mrok-0.2.3 → mrok-0.3.0}/mrok/cli/commands/agent/run/__init__.py +0 -0
- {mrok-0.2.3 → mrok-0.3.0}/mrok/cli/commands/agent/run/asgi.py +0 -0
- {mrok-0.2.3 → mrok-0.3.0}/mrok/cli/commands/agent/run/sidecar.py +0 -0
- {mrok-0.2.3 → mrok-0.3.0}/mrok/cli/commands/controller/__init__.py +0 -0
- {mrok-0.2.3 → mrok-0.3.0}/mrok/cli/commands/controller/openapi.py +0 -0
- {mrok-0.2.3 → mrok-0.3.0}/mrok/cli/commands/controller/run.py +0 -0
- {mrok-0.2.3 → mrok-0.3.0}/mrok/cli/main.py +0 -0
- {mrok-0.2.3 → mrok-0.3.0}/mrok/cli/rich.py +0 -0
- {mrok-0.2.3 → mrok-0.3.0}/mrok/conf.py +0 -0
- {mrok-0.2.3 → mrok-0.3.0}/mrok/controller/__init__.py +0 -0
- {mrok-0.2.3 → mrok-0.3.0}/mrok/controller/app.py +0 -0
- {mrok-0.2.3 → mrok-0.3.0}/mrok/controller/auth.py +0 -0
- {mrok-0.2.3 → mrok-0.3.0}/mrok/controller/dependencies/__init__.py +0 -0
- {mrok-0.2.3 → mrok-0.3.0}/mrok/controller/dependencies/conf.py +0 -0
- {mrok-0.2.3 → mrok-0.3.0}/mrok/controller/dependencies/ziti.py +0 -0
- {mrok-0.2.3 → mrok-0.3.0}/mrok/controller/openapi/__init__.py +0 -0
- {mrok-0.2.3 → mrok-0.3.0}/mrok/controller/openapi/examples.py +0 -0
- {mrok-0.2.3 → mrok-0.3.0}/mrok/controller/openapi/utils.py +0 -0
- {mrok-0.2.3 → mrok-0.3.0}/mrok/controller/pagination.py +0 -0
- {mrok-0.2.3 → mrok-0.3.0}/mrok/controller/routes/__init__.py +0 -0
- {mrok-0.2.3 → mrok-0.3.0}/mrok/controller/routes/instances.py +0 -0
- {mrok-0.2.3 → mrok-0.3.0}/mrok/controller/schemas.py +0 -0
- {mrok-0.2.3 → mrok-0.3.0}/mrok/errors.py +0 -0
- {mrok-0.2.3 → mrok-0.3.0}/mrok/http/__init__.py +0 -0
- {mrok-0.2.3 → mrok-0.3.0}/mrok/http/config.py +0 -0
- {mrok-0.2.3 → mrok-0.3.0}/mrok/http/forwarder.py +0 -0
- {mrok-0.2.3 → mrok-0.3.0}/mrok/http/lifespan.py +0 -0
- {mrok-0.2.3 → mrok-0.3.0}/mrok/http/master.py +0 -0
- {mrok-0.2.3 → mrok-0.3.0}/mrok/http/protocol.py +0 -0
- {mrok-0.2.3 → mrok-0.3.0}/mrok/http/server.py +0 -0
- {mrok-0.2.3 → mrok-0.3.0}/mrok/logging.py +0 -0
- {mrok-0.2.3 → mrok-0.3.0}/mrok/ziti/__init__.py +0 -0
- {mrok-0.2.3 → mrok-0.3.0}/mrok/ziti/api.py +0 -0
- {mrok-0.2.3 → mrok-0.3.0}/mrok/ziti/bootstrap.py +0 -0
- {mrok-0.2.3 → mrok-0.3.0}/mrok/ziti/constants.py +0 -0
- {mrok-0.2.3 → mrok-0.3.0}/mrok/ziti/errors.py +0 -0
- {mrok-0.2.3 → mrok-0.3.0}/mrok/ziti/pki.py +0 -0
- {mrok-0.2.3 → mrok-0.3.0}/prod.Dockerfile +0 -0
- {mrok-0.2.3 → mrok-0.3.0}/scripts/ziti.sh +0 -0
- {mrok-0.2.3 → mrok-0.3.0}/sonar-project.properties +0 -0
- {mrok-0.2.3 → mrok-0.3.0}/tests/__init__.py +0 -0
- {mrok-0.2.3 → mrok-0.3.0}/tests/agent/__init__.py +0 -0
- {mrok-0.2.3 → mrok-0.3.0}/tests/agent/sidecar/__init__.py +0 -0
- {mrok-0.2.3 → mrok-0.3.0}/tests/agent/sidecar/test_app.py +0 -0
- {mrok-0.2.3 → mrok-0.3.0}/tests/agent/sidecar/test_main.py +0 -0
- {mrok-0.2.3 → mrok-0.3.0}/tests/agent/test_ziticorn.py +0 -0
- {mrok-0.2.3 → mrok-0.3.0}/tests/cli/__init__.py +0 -0
- {mrok-0.2.3 → mrok-0.3.0}/tests/cli/admin/__init__.py +0 -0
- {mrok-0.2.3 → mrok-0.3.0}/tests/cli/admin/test_bootstrap.py +0 -0
- {mrok-0.2.3 → mrok-0.3.0}/tests/cli/admin/test_utils.py +0 -0
- {mrok-0.2.3 → mrok-0.3.0}/tests/cli/agent/__init__.py +0 -0
- {mrok-0.2.3 → mrok-0.3.0}/tests/cli/agent/test_run.py +0 -0
- {mrok-0.2.3 → mrok-0.3.0}/tests/cli/controller/__init__.py +0 -0
- {mrok-0.2.3 → mrok-0.3.0}/tests/cli/controller/test_openapi.py +0 -0
- {mrok-0.2.3 → mrok-0.3.0}/tests/cli/controller/test_run.py +0 -0
- {mrok-0.2.3 → mrok-0.3.0}/tests/cli/test_main.py +0 -0
- {mrok-0.2.3 → mrok-0.3.0}/tests/conftest.py +0 -0
- {mrok-0.2.3 → mrok-0.3.0}/tests/controller/__init__.py +0 -0
- {mrok-0.2.3 → mrok-0.3.0}/tests/controller/test_auth.py +0 -0
- {mrok-0.2.3 → mrok-0.3.0}/tests/controller/test_instances.py +0 -0
- {mrok-0.2.3 → mrok-0.3.0}/tests/controller/test_openapi.py +0 -0
- {mrok-0.2.3 → mrok-0.3.0}/tests/http/__init__.py +0 -0
- {mrok-0.2.3 → mrok-0.3.0}/tests/http/test_config.py +0 -0
- {mrok-0.2.3 → mrok-0.3.0}/tests/http/test_forwarder.py +0 -0
- {mrok-0.2.3 → mrok-0.3.0}/tests/http/test_lifespan.py +0 -0
- {mrok-0.2.3 → mrok-0.3.0}/tests/http/test_master.py +0 -0
- {mrok-0.2.3 → mrok-0.3.0}/tests/http/test_protocol.py +0 -0
- {mrok-0.2.3 → mrok-0.3.0}/tests/http/test_server.py +0 -0
- {mrok-0.2.3 → mrok-0.3.0}/tests/ziti/__init__.py +0 -0
- {mrok-0.2.3 → mrok-0.3.0}/tests/ziti/test_api.py +0 -0
- {mrok-0.2.3 → mrok-0.3.0}/tests/ziti/test_bootstrap.py +0 -0
- {mrok-0.2.3 → mrok-0.3.0}/tests/ziti/test_pki.py +0 -0
- {mrok-0.2.3 → mrok-0.3.0}/uv.lock +0 -0
|
@@ -21,7 +21,11 @@ from mrok.ziti.constants import (
|
|
|
21
21
|
|
|
22
22
|
|
|
23
23
|
async def get_instances(
|
|
24
|
-
settings: Settings,
|
|
24
|
+
settings: Settings,
|
|
25
|
+
detailed: bool,
|
|
26
|
+
extension: str | None = None,
|
|
27
|
+
tags: list[str] | None = None,
|
|
28
|
+
online_only: bool = False,
|
|
25
29
|
) -> list[dict]:
|
|
26
30
|
async with ZitiManagementAPI(settings) as api:
|
|
27
31
|
tags = tags or []
|
|
@@ -29,6 +33,9 @@ async def get_instances(
|
|
|
29
33
|
identities = [
|
|
30
34
|
identity async for identity in api.identities(params={"filter": tags_to_filter(tags)})
|
|
31
35
|
]
|
|
36
|
+
if online_only:
|
|
37
|
+
identities = list(filter(lambda i: i["hasEdgeRouterConnection"], identities))
|
|
38
|
+
|
|
32
39
|
if detailed or extension:
|
|
33
40
|
for identity in identities:
|
|
34
41
|
identity["services"] = [
|
|
@@ -60,10 +67,11 @@ async def get_instances(
|
|
|
60
67
|
def render_tsv(instances: list[dict], detailed: bool) -> None:
|
|
61
68
|
console = get_console()
|
|
62
69
|
if detailed:
|
|
63
|
-
console.print("id\tname\tservices\tpolicies\ttags\tcreated\tupdated")
|
|
70
|
+
console.print("id\tname\tstatus\tservices\tpolicies\ttags\tcreated\tupdated")
|
|
64
71
|
for instance in instances:
|
|
65
72
|
console.print(
|
|
66
73
|
f"{instance['id']}\t{instance['name']}\t"
|
|
74
|
+
f"{'online' if instance['hasEdgeRouterConnection'] else 'offline'}\t"
|
|
67
75
|
f"{extract_names(instance['services'], ', ')}\t"
|
|
68
76
|
f"{extract_names(instance['policies'], ', ')}\t"
|
|
69
77
|
f"{format_tags(instance['tags'], ', ')}\t"
|
|
@@ -71,10 +79,11 @@ def render_tsv(instances: list[dict], detailed: bool) -> None:
|
|
|
71
79
|
f"{format_timestamp(instance['updatedAt'])}"
|
|
72
80
|
)
|
|
73
81
|
else:
|
|
74
|
-
console.print("id\tname\ttags\tcreated")
|
|
82
|
+
console.print("id\tname\tstatus\ttags\tcreated")
|
|
75
83
|
for instance in instances:
|
|
76
84
|
console.print(
|
|
77
85
|
f"{instance['id']}\t{instance['name']}\t"
|
|
86
|
+
f"{'online' if instance['hasEdgeRouterConnection'] else 'offline'}\t"
|
|
78
87
|
f"{format_tags(instance['tags'], ', ')}\t"
|
|
79
88
|
f"{format_timestamp(instance['createdAt'])}\t"
|
|
80
89
|
)
|
|
@@ -90,6 +99,7 @@ def render_table(instances: list[dict], detailed: bool) -> None:
|
|
|
90
99
|
)
|
|
91
100
|
table.add_column("Id", style="green")
|
|
92
101
|
table.add_column("Name", style="bold cyan")
|
|
102
|
+
table.add_column("Status", justify="center")
|
|
93
103
|
if detailed:
|
|
94
104
|
table.add_column("Associated services")
|
|
95
105
|
table.add_column("Associated service policies")
|
|
@@ -102,6 +112,7 @@ def render_table(instances: list[dict], detailed: bool) -> None:
|
|
|
102
112
|
row = [
|
|
103
113
|
instance["id"],
|
|
104
114
|
instance["name"],
|
|
115
|
+
"🟢" if instance["hasEdgeRouterConnection"] else "⚪",
|
|
105
116
|
]
|
|
106
117
|
if detailed:
|
|
107
118
|
row += [
|
|
@@ -142,6 +153,15 @@ def register(app: typer.Typer) -> None:
|
|
|
142
153
|
show_default=True,
|
|
143
154
|
),
|
|
144
155
|
] = None,
|
|
156
|
+
online_only: Annotated[
|
|
157
|
+
bool,
|
|
158
|
+
typer.Option(
|
|
159
|
+
"--online-only",
|
|
160
|
+
"-o",
|
|
161
|
+
help="Show only connected instances",
|
|
162
|
+
show_default=True,
|
|
163
|
+
),
|
|
164
|
+
] = False,
|
|
145
165
|
detailed: bool = typer.Option(
|
|
146
166
|
False,
|
|
147
167
|
"--detailed",
|
|
@@ -155,7 +175,7 @@ def register(app: typer.Typer) -> None:
|
|
|
155
175
|
),
|
|
156
176
|
):
|
|
157
177
|
"""List instances in OpenZiti (identities)."""
|
|
158
|
-
instances = asyncio.run(get_instances(ctx.obj, detailed, extension, tags))
|
|
178
|
+
instances = asyncio.run(get_instances(ctx.obj, detailed, extension, tags, online_only))
|
|
159
179
|
|
|
160
180
|
if len(instances) == 0:
|
|
161
181
|
get_console().print("No instances found.")
|
|
@@ -8,14 +8,14 @@ from rich import print
|
|
|
8
8
|
from mrok.cli.commands.admin.utils import parse_tags
|
|
9
9
|
from mrok.conf import Settings
|
|
10
10
|
from mrok.ziti.api import ZitiManagementAPI
|
|
11
|
-
from mrok.ziti.services import
|
|
11
|
+
from mrok.ziti.services import register_service
|
|
12
12
|
|
|
13
13
|
RE_EXTENSION_ID = re.compile(r"(?i)EXT-\d{4}-\d{4}")
|
|
14
14
|
|
|
15
15
|
|
|
16
16
|
async def do_register(settings: Settings, extension_id: str, tags: list[str] | None):
|
|
17
17
|
async with ZitiManagementAPI(settings) as api:
|
|
18
|
-
await
|
|
18
|
+
await register_service(settings, api, extension_id, tags=parse_tags(tags))
|
|
19
19
|
|
|
20
20
|
|
|
21
21
|
def validate_extension_id(extension_id: str) -> str:
|
|
@@ -9,7 +9,7 @@ import typer
|
|
|
9
9
|
from mrok.cli.commands.admin.utils import parse_tags
|
|
10
10
|
from mrok.conf import Settings
|
|
11
11
|
from mrok.ziti.api import ZitiClientAPI, ZitiManagementAPI
|
|
12
|
-
from mrok.ziti.identities import
|
|
12
|
+
from mrok.ziti.identities import register_identity
|
|
13
13
|
|
|
14
14
|
RE_EXTENSION_ID = re.compile(r"(?i)EXT-\d{4}-\d{4}")
|
|
15
15
|
|
|
@@ -18,8 +18,8 @@ async def do_register(
|
|
|
18
18
|
settings: Settings, extension_id: str, instance_id: str, tags: list[str] | None
|
|
19
19
|
):
|
|
20
20
|
async with ZitiManagementAPI(settings) as mgmt_api, ZitiClientAPI(settings) as client_api:
|
|
21
|
-
return await
|
|
22
|
-
mgmt_api, client_api, extension_id, instance_id, tags=parse_tags(tags)
|
|
21
|
+
return await register_identity(
|
|
22
|
+
settings, mgmt_api, client_api, extension_id, instance_id, tags=parse_tags(tags)
|
|
23
23
|
)
|
|
24
24
|
|
|
25
25
|
|
|
@@ -5,14 +5,14 @@ import typer
|
|
|
5
5
|
|
|
6
6
|
from mrok.conf import Settings
|
|
7
7
|
from mrok.ziti.api import ZitiManagementAPI
|
|
8
|
-
from mrok.ziti.services import
|
|
8
|
+
from mrok.ziti.services import unregister_service
|
|
9
9
|
|
|
10
10
|
RE_EXTENSION_ID = re.compile(r"(?i)EXT-\d{4}-\d{4}")
|
|
11
11
|
|
|
12
12
|
|
|
13
13
|
async def do_unregister(settings: Settings, extension_id: str):
|
|
14
14
|
async with ZitiManagementAPI(settings) as api:
|
|
15
|
-
await
|
|
15
|
+
await unregister_service(settings, api, extension_id)
|
|
16
16
|
|
|
17
17
|
|
|
18
18
|
def validate_extension_id(extension_id: str):
|
|
@@ -5,14 +5,14 @@ import typer
|
|
|
5
5
|
|
|
6
6
|
from mrok.conf import Settings
|
|
7
7
|
from mrok.ziti.api import ZitiManagementAPI
|
|
8
|
-
from mrok.ziti.identities import
|
|
8
|
+
from mrok.ziti.identities import unregister_identity
|
|
9
9
|
|
|
10
10
|
RE_EXTENSION_ID = re.compile(r"(?i)EXT-\d{4}-\d{4}")
|
|
11
11
|
|
|
12
12
|
|
|
13
13
|
async def do_unregister(settings: Settings, extension_id: str, instance_id: str):
|
|
14
14
|
async with ZitiManagementAPI(settings) as api:
|
|
15
|
-
await
|
|
15
|
+
await unregister_identity(settings, api, extension_id, instance_id)
|
|
16
16
|
|
|
17
17
|
|
|
18
18
|
def validate_extension_id(extension_id: str):
|
|
@@ -14,8 +14,8 @@ from mrok.ziti.errors import (
|
|
|
14
14
|
ServiceAlreadyRegisteredError,
|
|
15
15
|
ServiceNotFoundError,
|
|
16
16
|
)
|
|
17
|
-
from mrok.ziti.identities import
|
|
18
|
-
from mrok.ziti.services import
|
|
17
|
+
from mrok.ziti.identities import register_identity, unregister_identity
|
|
18
|
+
from mrok.ziti.services import register_service, unregister_service
|
|
19
19
|
|
|
20
20
|
logger = logging.getLogger("mrok.controller")
|
|
21
21
|
|
|
@@ -83,7 +83,7 @@ async def create_extension(
|
|
|
83
83
|
],
|
|
84
84
|
):
|
|
85
85
|
try:
|
|
86
|
-
service = await
|
|
86
|
+
service = await register_service(settings, mgmt_api, data.extension.id, data.tags)
|
|
87
87
|
return ExtensionRead(
|
|
88
88
|
id=service["id"],
|
|
89
89
|
name=service["name"],
|
|
@@ -149,7 +149,7 @@ async def delete_instance_by_id_or_extension_id(
|
|
|
149
149
|
id_or_extension_id: str,
|
|
150
150
|
):
|
|
151
151
|
try:
|
|
152
|
-
await
|
|
152
|
+
await unregister_service(settings, mgmt_api, id_or_extension_id)
|
|
153
153
|
except ServiceNotFoundError:
|
|
154
154
|
raise HTTPException(
|
|
155
155
|
status_code=status.HTTP_404_NOT_FOUND,
|
|
@@ -203,6 +203,7 @@ async def get_extensions(
|
|
|
203
203
|
tags=["Instances"],
|
|
204
204
|
)
|
|
205
205
|
async def create_extension_instances(
|
|
206
|
+
settings: AppSettings,
|
|
206
207
|
mgmt_api: ZitiManagementAPI,
|
|
207
208
|
client_api: ZitiClientAPI,
|
|
208
209
|
id_or_extension_id: str,
|
|
@@ -223,8 +224,8 @@ async def create_extension_instances(
|
|
|
223
224
|
],
|
|
224
225
|
):
|
|
225
226
|
service = await fetch_extension_or_404(mgmt_api, id_or_extension_id)
|
|
226
|
-
identity, identity_file = await
|
|
227
|
-
mgmt_api, client_api, service["name"], data.instance.id, data.tags
|
|
227
|
+
identity, identity_file = await register_identity(
|
|
228
|
+
settings, mgmt_api, client_api, service["name"], data.instance.id, data.tags
|
|
228
229
|
)
|
|
229
230
|
return InstanceRead(
|
|
230
231
|
id=identity["id"],
|
|
@@ -299,10 +300,11 @@ async def get_instance_by_id_or_instance_id(
|
|
|
299
300
|
tags=["Instances"],
|
|
300
301
|
)
|
|
301
302
|
async def delete_instance_by_id_or_instance_id(
|
|
303
|
+
settings: AppSettings,
|
|
302
304
|
mgmt_api: ZitiManagementAPI,
|
|
303
305
|
id_or_extension_id: str,
|
|
304
306
|
id_or_instance_id: str,
|
|
305
307
|
):
|
|
306
308
|
identity = await fetch_instance_or_404(mgmt_api, id_or_extension_id, id_or_instance_id)
|
|
307
309
|
instance_id, extension_id = identity["name"].split(".")
|
|
308
|
-
await
|
|
310
|
+
await unregister_identity(settings, mgmt_api, extension_id, instance_id)
|
|
@@ -1,8 +1,10 @@
|
|
|
1
|
+
import copy
|
|
1
2
|
import logging
|
|
2
3
|
from typing import Any
|
|
3
4
|
|
|
4
5
|
import jwt
|
|
5
6
|
|
|
7
|
+
from mrok.conf import Settings
|
|
6
8
|
from mrok.ziti import pki
|
|
7
9
|
from mrok.ziti.api import TagsType, ZitiClientAPI, ZitiManagementAPI
|
|
8
10
|
from mrok.ziti.constants import (
|
|
@@ -16,31 +18,37 @@ from mrok.ziti.errors import (
|
|
|
16
18
|
ServiceNotFoundError,
|
|
17
19
|
UserIdentityNotFoundError,
|
|
18
20
|
)
|
|
21
|
+
from mrok.ziti.services import register_service, unregister_service
|
|
19
22
|
|
|
20
23
|
logger = logging.getLogger("mrok.ziti")
|
|
21
24
|
|
|
22
25
|
|
|
23
|
-
async def
|
|
26
|
+
async def register_identity(
|
|
27
|
+
settings: Settings,
|
|
24
28
|
mgmt_api: ZitiManagementAPI,
|
|
25
29
|
client_api: ZitiClientAPI,
|
|
26
|
-
|
|
27
|
-
|
|
30
|
+
service_external_id: str,
|
|
31
|
+
identity_external_id: str,
|
|
28
32
|
tags: TagsType | None = None,
|
|
29
33
|
):
|
|
30
|
-
service_name =
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
+
service_name = service_external_id.lower()
|
|
35
|
+
identity_tags = copy.copy(tags or {})
|
|
36
|
+
identity_tags[MROK_SERVICE_TAG_NAME] = service_name
|
|
37
|
+
identity_tags[MROK_IDENTITY_TYPE_TAG_NAME] = MROK_IDENTITY_TYPE_TAG_VALUE_INSTANCE
|
|
34
38
|
service = await mgmt_api.search_service(service_name)
|
|
35
39
|
if not service:
|
|
36
|
-
raise ServiceNotFoundError(f"A service with name `{
|
|
40
|
+
raise ServiceNotFoundError(f"A service with name `{service_external_id}` does not exists.")
|
|
37
41
|
|
|
38
|
-
identity_name = f"{
|
|
42
|
+
identity_name = f"{identity_external_id.lower()}.{service_name}"
|
|
39
43
|
service_policy_name = f"{identity_name}:bind"
|
|
44
|
+
self_service_policy_name = f"self.{service_policy_name}"
|
|
40
45
|
|
|
41
46
|
identity = await mgmt_api.search_identity(identity_name)
|
|
42
47
|
if identity:
|
|
43
48
|
service_policy = await mgmt_api.search_service_policy(service_policy_name)
|
|
49
|
+
if service_policy:
|
|
50
|
+
await mgmt_api.delete_service_policy(service_policy["id"])
|
|
51
|
+
service_policy = await mgmt_api.search_service_policy(self_service_policy_name)
|
|
44
52
|
if service_policy:
|
|
45
53
|
await mgmt_api.delete_service_policy(service_policy["id"])
|
|
46
54
|
router_policy = await mgmt_api.search_router_policy(identity_name)
|
|
@@ -48,7 +56,7 @@ async def register_instance(
|
|
|
48
56
|
await mgmt_api.delete_router_policy(router_policy["id"])
|
|
49
57
|
await mgmt_api.delete_identity(identity["id"])
|
|
50
58
|
|
|
51
|
-
identity_id = await mgmt_api.create_user_identity(identity_name, tags=
|
|
59
|
+
identity_id = await mgmt_api.create_user_identity(identity_name, tags=identity_tags)
|
|
52
60
|
identity = await mgmt_api.get_identity(identity_id)
|
|
53
61
|
|
|
54
62
|
identity_json = await _enroll_identity(
|
|
@@ -58,33 +66,55 @@ async def register_instance(
|
|
|
58
66
|
identity,
|
|
59
67
|
mrok={
|
|
60
68
|
"identity": identity_name,
|
|
61
|
-
"extension":
|
|
62
|
-
"instance":
|
|
69
|
+
"extension": service_external_id,
|
|
70
|
+
"instance": identity_external_id,
|
|
71
|
+
"domain": settings.proxy.domain,
|
|
72
|
+
"tags": identity_tags,
|
|
63
73
|
},
|
|
64
74
|
)
|
|
65
75
|
|
|
76
|
+
self_service = await mgmt_api.search_service(identity_name)
|
|
77
|
+
if not self_service:
|
|
78
|
+
self_service = await register_service(settings, mgmt_api, identity_name, tags)
|
|
79
|
+
|
|
66
80
|
await mgmt_api.create_bind_service_policy(service_policy_name, service["id"], identity_id)
|
|
81
|
+
await mgmt_api.create_bind_service_policy(
|
|
82
|
+
self_service_policy_name,
|
|
83
|
+
self_service["id"],
|
|
84
|
+
identity_id,
|
|
85
|
+
)
|
|
67
86
|
await mgmt_api.create_router_policy(identity_name, identity_id)
|
|
68
87
|
|
|
69
88
|
return identity, identity_json
|
|
70
89
|
|
|
71
90
|
|
|
72
|
-
async def
|
|
91
|
+
async def unregister_identity(
|
|
92
|
+
settings: Settings,
|
|
73
93
|
mgmt_api: ZitiManagementAPI,
|
|
74
|
-
|
|
75
|
-
|
|
94
|
+
service_external_id: str,
|
|
95
|
+
identity_external_id: str,
|
|
76
96
|
):
|
|
77
|
-
service_name =
|
|
97
|
+
service_name = service_external_id.lower()
|
|
78
98
|
service = await mgmt_api.search_service(service_name)
|
|
79
99
|
if not service:
|
|
80
|
-
raise ServiceNotFoundError(f"A service with name `{
|
|
100
|
+
raise ServiceNotFoundError(f"A service with name `{service_external_id}` does not exists.")
|
|
81
101
|
|
|
82
|
-
identity_name = f"{
|
|
102
|
+
identity_name = f"{identity_external_id.lower()}.{service_name}"
|
|
83
103
|
service_policy_name = f"{identity_name}:bind"
|
|
84
104
|
|
|
85
105
|
identity = await mgmt_api.search_identity(identity_name)
|
|
86
106
|
if not identity:
|
|
87
|
-
raise UserIdentityNotFoundError(f"
|
|
107
|
+
raise UserIdentityNotFoundError(f"Identity `{identity_external_id}` not found.")
|
|
108
|
+
|
|
109
|
+
self_service_policy_name = f"self.{service_policy_name}"
|
|
110
|
+
|
|
111
|
+
service_policy = await mgmt_api.search_service_policy(self_service_policy_name)
|
|
112
|
+
if service_policy:
|
|
113
|
+
await mgmt_api.delete_service_policy(service_policy["id"])
|
|
114
|
+
|
|
115
|
+
self_service = await mgmt_api.search_service(identity_name)
|
|
116
|
+
if self_service:
|
|
117
|
+
await unregister_service(settings, mgmt_api, identity_name)
|
|
88
118
|
|
|
89
119
|
service_policy = await mgmt_api.search_service_policy(service_policy_name)
|
|
90
120
|
if service_policy:
|
|
@@ -120,7 +150,7 @@ async def _enroll_identity(
|
|
|
120
150
|
client_api: ZitiClientAPI,
|
|
121
151
|
identity_id: str,
|
|
122
152
|
identity: dict[str, Any] | None = None,
|
|
123
|
-
mrok: dict[str, str] | None = None,
|
|
153
|
+
mrok: dict[str, str | dict] | None = None,
|
|
124
154
|
):
|
|
125
155
|
if identity is None:
|
|
126
156
|
identity = await mgmt_api.get_identity(identity_id)
|
|
@@ -13,10 +13,10 @@ from mrok.ziti.errors import (
|
|
|
13
13
|
logger = logging.getLogger(__name__)
|
|
14
14
|
|
|
15
15
|
|
|
16
|
-
async def
|
|
17
|
-
settings: Settings, mgmt_api: ZitiManagementAPI,
|
|
16
|
+
async def register_service(
|
|
17
|
+
settings: Settings, mgmt_api: ZitiManagementAPI, external_id: str, tags: TagsType | None
|
|
18
18
|
) -> dict[str, Any]:
|
|
19
|
-
service_name =
|
|
19
|
+
service_name = external_id.lower()
|
|
20
20
|
registered = False
|
|
21
21
|
proxy_identity = await mgmt_api.search_identity(settings.proxy.identity)
|
|
22
22
|
if not proxy_identity:
|
|
@@ -58,17 +58,17 @@ async def register_extension(
|
|
|
58
58
|
await mgmt_api.create_service_router_policy(service_name, service_id, tags=tags)
|
|
59
59
|
registered = True
|
|
60
60
|
if not registered:
|
|
61
|
-
raise ServiceAlreadyRegisteredError(f"
|
|
61
|
+
raise ServiceAlreadyRegisteredError(f"Service `{external_id}` already registered.")
|
|
62
62
|
return service
|
|
63
63
|
|
|
64
64
|
|
|
65
|
-
async def
|
|
66
|
-
settings: Settings, mgmt_api: ZitiManagementAPI,
|
|
65
|
+
async def unregister_service(
|
|
66
|
+
settings: Settings, mgmt_api: ZitiManagementAPI, external_id: str
|
|
67
67
|
) -> None:
|
|
68
|
-
service_name =
|
|
68
|
+
service_name = external_id.lower()
|
|
69
69
|
service = await mgmt_api.search_service(service_name)
|
|
70
70
|
if not service:
|
|
71
|
-
raise ServiceNotFoundError(f"
|
|
71
|
+
raise ServiceNotFoundError(f"Service `{external_id}` not found.")
|
|
72
72
|
|
|
73
73
|
router_policy = await mgmt_api.search_service_router_policy(service_name)
|
|
74
74
|
if router_policy:
|
|
@@ -162,8 +162,8 @@ def test_list_instances_command(
|
|
|
162
162
|
):
|
|
163
163
|
settings = settings_factory()
|
|
164
164
|
mocker.patch("mrok.cli.main.get_settings", return_value=settings)
|
|
165
|
-
|
|
166
|
-
|
|
165
|
+
mock_get = mocker.patch(
|
|
166
|
+
"mrok.cli.commands.admin.list.instances.get_instances",
|
|
167
167
|
return_value=[
|
|
168
168
|
{
|
|
169
169
|
"id": "idt",
|
|
@@ -171,15 +171,12 @@ def test_list_instances_command(
|
|
|
171
171
|
"tags": [],
|
|
172
172
|
"services": [],
|
|
173
173
|
"policies": [],
|
|
174
|
+
"hasEdgeRouterConnection": False,
|
|
174
175
|
"createdAt": "2025-10-13T09:51:06.175Z",
|
|
175
176
|
"updatedAt": "2025-10-13T09:51:06.175Z",
|
|
176
177
|
},
|
|
177
178
|
],
|
|
178
179
|
)
|
|
179
|
-
mocker.patch(
|
|
180
|
-
"mrok.cli.commands.admin.list.instances.get_instances",
|
|
181
|
-
new=mock_get,
|
|
182
|
-
)
|
|
183
180
|
|
|
184
181
|
runner = CliRunner()
|
|
185
182
|
# Run the command
|
|
@@ -187,9 +184,8 @@ def test_list_instances_command(
|
|
|
187
184
|
app,
|
|
188
185
|
shlex.split(f"admin list instances {output} {detailed}"),
|
|
189
186
|
)
|
|
190
|
-
|
|
191
187
|
assert result.exit_code == 0
|
|
192
|
-
mock_get.assert_called_once_with(settings, detailed == "-d", None, None)
|
|
188
|
+
mock_get.assert_called_once_with(settings, detailed == "-d", None, None, False)
|
|
193
189
|
|
|
194
190
|
|
|
195
191
|
def test_list_instances_command_with_tag(
|
|
@@ -213,11 +209,14 @@ def test_list_instances_command_with_tag(
|
|
|
213
209
|
)
|
|
214
210
|
|
|
215
211
|
assert "No instances found" in result.output
|
|
216
|
-
mock_get.assert_called_once_with(settings, False, None, ["mytag=v1"])
|
|
212
|
+
mock_get.assert_called_once_with(settings, False, None, ["mytag=v1"], False)
|
|
217
213
|
|
|
218
214
|
|
|
219
215
|
@pytest.mark.asyncio
|
|
220
|
-
async def
|
|
216
|
+
async def test_list_instances_with_extension_filter(
|
|
217
|
+
settings_factory: SettingsFactory,
|
|
218
|
+
httpx_mock: HTTPXMock,
|
|
219
|
+
):
|
|
221
220
|
settings = settings_factory()
|
|
222
221
|
tag_filter = f'tags.{MROK_IDENTITY_TYPE_TAG_NAME}="{MROK_IDENTITY_TYPE_TAG_VALUE_INSTANCE}"'
|
|
223
222
|
url = f"{settings.ziti.api.management}/edge/management/v1/identities"
|
|
@@ -230,17 +229,35 @@ async def test_list_instances(settings_factory: SettingsFactory, httpx_mock: HTT
|
|
|
230
229
|
"data": [{"id": "idt", "name": "identity"}],
|
|
231
230
|
},
|
|
232
231
|
)
|
|
232
|
+
httpx_mock.add_response(
|
|
233
|
+
method="GET",
|
|
234
|
+
url=f"{url}/idt/services?limit=5&offset=0",
|
|
235
|
+
json={
|
|
236
|
+
"meta": {"pagination": {"totalCount": 1, "limit": 5, "offset": 0}},
|
|
237
|
+
"data": [{"id": "svc", "name": "svc"}],
|
|
238
|
+
},
|
|
239
|
+
)
|
|
240
|
+
httpx_mock.add_response(
|
|
241
|
+
method="GET",
|
|
242
|
+
url=f"{url}/idt/service-policies?limit=5&offset=0",
|
|
243
|
+
json={
|
|
244
|
+
"meta": {"pagination": {"totalCount": 1, "limit": 5, "offset": 0}},
|
|
245
|
+
"data": [{"id": "plc", "name": "svc-policy"}],
|
|
246
|
+
},
|
|
247
|
+
)
|
|
233
248
|
|
|
234
|
-
instances = await get_instances(settings, False)
|
|
249
|
+
instances = await get_instances(settings, False, "svc")
|
|
235
250
|
assert len(instances) == 1
|
|
236
251
|
assert instances[0] == {
|
|
237
252
|
"id": "idt",
|
|
238
253
|
"name": "identity",
|
|
254
|
+
"services": [{"id": "svc", "name": "svc"}],
|
|
255
|
+
"policies": [{"id": "plc", "name": "svc-policy"}],
|
|
239
256
|
}
|
|
240
257
|
|
|
241
258
|
|
|
242
259
|
@pytest.mark.asyncio
|
|
243
|
-
async def
|
|
260
|
+
async def test_list_instances_with_online_only_filter(
|
|
244
261
|
settings_factory: SettingsFactory,
|
|
245
262
|
httpx_mock: HTTPXMock,
|
|
246
263
|
):
|
|
@@ -252,8 +269,11 @@ async def test_list_instances_with_extension_filter(
|
|
|
252
269
|
method="GET",
|
|
253
270
|
url=f"{url}?filter={tag_filter}&limit=5&offset=0",
|
|
254
271
|
json={
|
|
255
|
-
"meta": {"pagination": {"totalCount":
|
|
256
|
-
"data": [
|
|
272
|
+
"meta": {"pagination": {"totalCount": 2, "limit": 5, "offset": 0}},
|
|
273
|
+
"data": [
|
|
274
|
+
{"id": "idt", "name": "identity", "hasEdgeRouterConnection": True},
|
|
275
|
+
{"id": "idt2", "name": "identity", "hasEdgeRouterConnection": False},
|
|
276
|
+
],
|
|
257
277
|
},
|
|
258
278
|
)
|
|
259
279
|
httpx_mock.add_response(
|
|
@@ -273,11 +293,12 @@ async def test_list_instances_with_extension_filter(
|
|
|
273
293
|
},
|
|
274
294
|
)
|
|
275
295
|
|
|
276
|
-
instances = await get_instances(settings, False, "svc")
|
|
296
|
+
instances = await get_instances(settings, False, "svc", online_only=True)
|
|
277
297
|
assert len(instances) == 1
|
|
278
298
|
assert instances[0] == {
|
|
279
299
|
"id": "idt",
|
|
280
300
|
"name": "identity",
|
|
281
301
|
"services": [{"id": "svc", "name": "svc"}],
|
|
282
302
|
"policies": [{"id": "plc", "name": "svc-policy"}],
|
|
303
|
+
"hasEdgeRouterConnection": True,
|
|
283
304
|
}
|
|
@@ -73,7 +73,7 @@ async def test_do_register_extension(mocker: MockerFixture, settings_factory: Se
|
|
|
73
73
|
return_value=mocked_api,
|
|
74
74
|
)
|
|
75
75
|
mocked_register_service = mocker.patch(
|
|
76
|
-
"mrok.cli.commands.admin.register.extensions.
|
|
76
|
+
"mrok.cli.commands.admin.register.extensions.register_service"
|
|
77
77
|
)
|
|
78
78
|
|
|
79
79
|
await do_register_extension(settings, "EXT-1234", ["tag=value"])
|
|
@@ -162,12 +162,17 @@ async def test_do_register_instance(mocker: MockerFixture, settings_factory: Set
|
|
|
162
162
|
return_value=mocked_cli_api,
|
|
163
163
|
)
|
|
164
164
|
mocked_register_instance = mocker.patch(
|
|
165
|
-
"mrok.cli.commands.admin.register.instances.
|
|
165
|
+
"mrok.cli.commands.admin.register.instances.register_identity",
|
|
166
166
|
)
|
|
167
167
|
|
|
168
168
|
await do_register_instance(settings, "EXT-1234", "INS-1234-0001", ["tag=value"])
|
|
169
169
|
mocked_register_instance.assert_awaited_once_with(
|
|
170
|
-
|
|
170
|
+
settings,
|
|
171
|
+
mocked_mgmt_api,
|
|
172
|
+
mocked_cli_api,
|
|
173
|
+
"EXT-1234",
|
|
174
|
+
"INS-1234-0001",
|
|
175
|
+
tags={"tag": "value"},
|
|
171
176
|
)
|
|
172
177
|
mocked_mgmt_api_ctor.assert_called_once_with(settings)
|
|
173
178
|
mocked_cli_api_ctor.assert_called_once_with(settings)
|
|
@@ -69,7 +69,7 @@ async def test_do_unregister_extension(mocker: MockerFixture, settings_factory:
|
|
|
69
69
|
return_value=mocked_api,
|
|
70
70
|
)
|
|
71
71
|
mocked_unregister_service = mocker.patch(
|
|
72
|
-
"mrok.cli.commands.admin.unregister.extensions.
|
|
72
|
+
"mrok.cli.commands.admin.unregister.extensions.unregister_service"
|
|
73
73
|
)
|
|
74
74
|
|
|
75
75
|
await do_unregister_extension(settings, "EXT-1234")
|
|
@@ -144,11 +144,12 @@ async def test_do_unregister_instance(mocker: MockerFixture, settings_factory: S
|
|
|
144
144
|
return_value=mocked_api,
|
|
145
145
|
)
|
|
146
146
|
mocked_unregister_service = mocker.patch(
|
|
147
|
-
"mrok.cli.commands.admin.unregister.instances.
|
|
147
|
+
"mrok.cli.commands.admin.unregister.instances.unregister_identity"
|
|
148
148
|
)
|
|
149
149
|
|
|
150
150
|
await do_unregister_instance(settings, "EXT-1234", "INS-1234-0001")
|
|
151
151
|
mocked_unregister_service.assert_awaited_once_with(
|
|
152
|
+
settings,
|
|
152
153
|
mocked_api,
|
|
153
154
|
"EXT-1234",
|
|
154
155
|
"INS-1234-0001",
|