Skip to content

Commit

Permalink
feat: add openservice mesh resources in support bundle (#471)
Browse files Browse the repository at this point in the history
  • Loading branch information
Elsie4ever authored Jan 3, 2025
1 parent cc68a59 commit 81ae30f
Show file tree
Hide file tree
Showing 10 changed files with 293 additions and 27 deletions.
4 changes: 4 additions & 0 deletions azext_edge/edge/_help.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@
ARCCONTAINERSTORAGE_API_V1,
CERTMANAGER_API_V1,
CONTAINERSTORAGE_API_V1,
OPENSERVICEMESH_CONFIG_API_V1,
OPENSERVICEMESH_POLICY_API_V1,
SECRETSTORE_API_V1,
SECRETSYNC_API_V1,
TRUSTMANAGER_API_V1,
Expand Down Expand Up @@ -66,6 +68,8 @@ def load_iotops_help():
- {COMPAT_DATAFLOW_APIS.as_str()}
- {ARCCONTAINERSTORAGE_API_V1.as_str()}
- {CONTAINERSTORAGE_API_V1.as_str()}
- {OPENSERVICEMESH_CONFIG_API_V1.as_str()}
- {OPENSERVICEMESH_POLICY_API_V1.as_str()}
- {SECRETSYNC_API_V1.as_str()}
- {SECRETSTORE_API_V1.as_str()}
- {TRUSTMANAGER_API_V1.as_str()}
Expand Down
1 change: 1 addition & 0 deletions azext_edge/edge/common.py
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,7 @@ class OpsServiceType(ListableEnum):
"""

mq = "broker"
openservicemesh = "openservicemesh"
opcua = "opcua"
akri = "akri"
deviceregistry = "deviceregistry"
Expand Down
3 changes: 3 additions & 0 deletions azext_edge/edge/providers/edge_api/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
from .clusterconfig import CLUSTER_CONFIG_API_V1
from .mq import MQ_ACTIVE_API, MQTT_BROKER_API_V1, MqResourceKinds
from .opcua import OPCUA_API_V1, OpcuaResourceKinds
from .openservicemesh import OPENSERVICEMESH_CONFIG_API_V1, OPENSERVICEMESH_POLICY_API_V1
from .keyvault import KEYVAULT_API_V1, KeyVaultResourceKinds
from .deviceregistry import DEVICEREGISTRY_API_V1, DeviceRegistryResourceKinds
from .dataflow import DATAFLOW_API_V1, DataflowResourceKinds
Expand All @@ -28,6 +29,8 @@
"MqResourceKinds",
"MQ_ACTIVE_API",
"MQTT_BROKER_API_V1",
"OPENSERVICEMESH_CONFIG_API_V1",
"OPENSERVICEMESH_POLICY_API_V1",
"OPCUA_API_V1",
"OpcuaResourceKinds",
"KeyVaultResourceKinds",
Expand Down
20 changes: 20 additions & 0 deletions azext_edge/edge/providers/edge_api/openservicemesh.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
# coding=utf-8
# ----------------------------------------------------------------------------------------------
# Copyright (c) Microsoft Corporation. All rights reserved.
# Licensed under the MIT License. See License file in the project root for license information.
# ----------------------------------------------------------------------------------------------

from .base import EdgeResourceApi


OPENSERVICEMESH_CONFIG_API_V1 = EdgeResourceApi(
group="config.openservicemesh.io",
version="v1alpha2",
moniker="openservicemesh",
)

OPENSERVICEMESH_POLICY_API_V1 = EdgeResourceApi(
group="policy.openservicemesh.io",
version="v1alpha1",
moniker="openservicemesh",
)
85 changes: 85 additions & 0 deletions azext_edge/edge/providers/support/openservicemesh.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
# coding=utf-8
# ----------------------------------------------------------------------------------------------
# Copyright (c) Microsoft Corporation. All rights reserved.
# Licensed under the MIT License. See License file in the project root for license information.
# ----------------------------------------------------------------------------------------------

from functools import partial
from typing import Iterable, Optional

from knack.log import get_logger

from ..edge_api import OPENSERVICEMESH_CONFIG_API_V1, EdgeResourceApi
from .base import (
DAY_IN_SECONDS,
assemble_crd_work,
process_config_maps,
process_deployments,
process_replicasets,
process_services,
process_v1_pods,
)

logger = get_logger(__name__)

OSM_DIRECTORY_PATH = OPENSERVICEMESH_CONFIG_API_V1.moniker
OSM_NAMESPACE = "arc-osm-system"


def fetch_deployments():
return process_deployments(
directory_path=OSM_DIRECTORY_PATH,
namespace=OSM_NAMESPACE,
)


def fetch_replicasets():
return process_replicasets(
directory_path=OSM_DIRECTORY_PATH,
namespace=OSM_NAMESPACE,
)


def fetch_pods(since_seconds: int = DAY_IN_SECONDS):
return process_v1_pods(
directory_path=OSM_DIRECTORY_PATH,
namespace=OSM_NAMESPACE,
since_seconds=since_seconds,
)


def fetch_services():
return process_services(
directory_path=OSM_DIRECTORY_PATH,
namespace=OSM_NAMESPACE,
)


def fetch_configmaps():
return process_config_maps(
directory_path=OSM_DIRECTORY_PATH,
namespace=OSM_NAMESPACE,
)


support_runtime_elements = {
"configmaps": fetch_configmaps,
"deployments": fetch_deployments,
"replicasets": fetch_replicasets,
"services": fetch_services,
}


def prepare_bundle(
log_age_seconds: int = DAY_IN_SECONDS,
apis: Optional[Iterable[EdgeResourceApi]] = None,
) -> dict:
osm_to_run = {}

if apis:
osm_to_run.update(assemble_crd_work(apis=apis))

support_runtime_elements["pods"] = partial(fetch_pods, since_seconds=log_age_seconds)
osm_to_run.update(support_runtime_elements)

return osm_to_run
8 changes: 8 additions & 0 deletions azext_edge/edge/providers/support_bundle.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@
CLUSTER_CONFIG_API_V1,
CONTAINERSTORAGE_API_V1,
MQTT_BROKER_API_V1,
OPENSERVICEMESH_CONFIG_API_V1,
OPENSERVICEMESH_POLICY_API_V1,
OPCUA_API_V1,
DEVICEREGISTRY_API_V1,
DATAFLOW_API_V1,
Expand All @@ -36,6 +38,7 @@
COMPAT_CERTMANAGER_APIS = EdgeApiManager(resource_apis=[CERTMANAGER_API_V1, TRUSTMANAGER_API_V1])
COMPAT_CLUSTER_CONFIG_APIS = EdgeApiManager(resource_apis=[CLUSTER_CONFIG_API_V1])
COMPAT_MQTT_BROKER_APIS = EdgeApiManager(resource_apis=[MQTT_BROKER_API_V1])
COMPAT_OSM_APIS = EdgeApiManager(resource_apis=[OPENSERVICEMESH_CONFIG_API_V1, OPENSERVICEMESH_POLICY_API_V1])
COMPAT_OPCUA_APIS = EdgeApiManager(resource_apis=[OPCUA_API_V1])
COMPAT_DEVICEREGISTRY_APIS = EdgeApiManager(resource_apis=[DEVICEREGISTRY_API_V1])
COMPAT_DATAFLOW_APIS = EdgeApiManager(resource_apis=[DATAFLOW_API_V1])
Expand All @@ -57,6 +60,7 @@ def build_bundle(

from .support.billing import prepare_bundle as prepare_billing_bundle
from .support.mq import prepare_bundle as prepare_mq_bundle
from .support.openservicemesh import prepare_bundle as prepare_openservicemesh_bundle
from .support.opcua import prepare_bundle as prepare_opcua_bundle
from .support.dataflow import prepare_bundle as prepare_dataflow_bundle
from .support.deviceregistry import prepare_bundle as prepare_deviceregistry_bundle
Expand Down Expand Up @@ -92,6 +96,10 @@ def collect_default_works(
"apis": COMPAT_CLUSTER_CONFIG_APIS,
"prepare_bundle": prepare_billing_bundle,
},
OpsServiceType.openservicemesh.value: {
"apis": COMPAT_OSM_APIS,
"prepare_bundle": prepare_openservicemesh_bundle,
},
OpsServiceType.opcua.value: {
"apis": COMPAT_OPCUA_APIS,
"prepare_bundle": prepare_opcua_bundle,
Expand Down
19 changes: 19 additions & 0 deletions azext_edge/tests/edge/support/create_bundle_int/helpers.py
Original file line number Diff line number Diff line change
Expand Up @@ -242,6 +242,7 @@ def get_file_map(
ssc_namespace = namespaces.get("ssc")
c_namespace = namespaces.get("usage_system")
certmanager_namespace = namespaces.get("certmanager")
osm_namespace = namespaces.get("osm")

if aio_namespace:
walk_result.pop(path.join(BASE_ZIP_PATH, aio_namespace))
Expand Down Expand Up @@ -305,6 +306,15 @@ def get_file_map(
file_map[OpsServiceType.azuremonitor.value] = convert_file_names(walk_result[monitor_path]["files"])
file_map["__namespaces__"][OpsServiceType.azuremonitor.value] = arc_namespace

# no files for aio, skip the rest assertions
return file_map
elif ops_service == OpsServiceType.openservicemesh.value:
# resources only in osm_namespace
assert len(walk_result) == 1 + expected_default_walk_result
osm_path = path.join(BASE_ZIP_PATH, osm_namespace, "openservicemesh")
file_map["osm"] = convert_file_names(walk_result[osm_path]["files"])
file_map["__namespaces__"]["osm"] = osm_namespace

# no files for aio, skip the rest assertions
return file_map
elif ops_service == "certmanager":
Expand Down Expand Up @@ -356,6 +366,7 @@ def process_top_levels(
acstor_namespace = None
ssc_namespace = None
certmanager_namespace = None
osm_namespace = None

def _get_namespace_determinating_files(name: str, folder: str, file_prefix: str) -> List[str]:
level1 = walk_result.get(path.join(BASE_ZIP_PATH, name, folder), {})
Expand Down Expand Up @@ -388,6 +399,10 @@ def _get_namespace_determinating_files(name: str, folder: str, file_prefix: str)
ssc_namespace = name
elif _get_namespace_determinating_files(name=name, folder=path.join("certmanager"), file_prefix="configmap"):
certmanager_namespace = name
elif _get_namespace_determinating_files(
name=name, folder=path.join("openservicemesh"), file_prefix="configmap"
):
osm_namespace = name
elif _get_namespace_determinating_files(name=name, folder="meta", file_prefix="instance"):
namespace = name

Expand Down Expand Up @@ -415,6 +430,7 @@ def _get_namespace_determinating_files(name: str, folder: str, file_prefix: str)
"ssc": ssc_namespace,
"usage_system": clusterconfig_namespace,
"certmanager": certmanager_namespace,
"osm": osm_namespace,
}

_clean_up_folders(
Expand All @@ -431,6 +447,7 @@ def _get_namespace_determinating_files(name: str, folder: str, file_prefix: str)
logger.debug(f"ACSTOR namespace: {acstor_namespace}")
logger.debug(f"SSC namespace: {ssc_namespace}")
logger.debug(f"Certmanager namespace: {certmanager_namespace}")
logger.debug(f"OSM namespace: {osm_namespace}")

return namespaces

Expand Down Expand Up @@ -508,6 +525,7 @@ def _clean_up_folders(
certmanager_namespace = namespaces.get("certmanager")
clusterconfig_namespace = namespaces.get("usage_system")
ssc_namespace = namespaces.get("ssc")
osm_namespace = namespaces.get("osm")

monitor_path = path.join(BASE_ZIP_PATH, arc_namespace, OpsServiceType.azuremonitor.value)
services = [OpsServiceType.certmanager.value] if certmanager_namespace else []
Expand All @@ -517,6 +535,7 @@ def _clean_up_folders(
(acs_namespace, ["arccontainerstorage"]),
(ssc_namespace, [OpsServiceType.secretstore.value]),
(certmanager_namespace, services),
(osm_namespace, ["openservicemesh"]),
]:
if namespace_folder:
# remove empty folders in level 1
Expand Down
39 changes: 12 additions & 27 deletions azext_edge/tests/edge/support/create_bundle_int/test_auto_int.py
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@ def test_create_bundle(init_setup, bundle_dir, mq_traces, ops_service, tracked_f
ssc_namespace = namespaces.get("ssc")
arc_namespace = namespaces.get("arc")
certmanager_namespace = namespaces.get("certmanager")
osm_namespace = namespaces.get("osm")

# Level 1
level_1 = walk_result.pop(path.join(BASE_ZIP_PATH, aio_namespace))
Expand All @@ -92,6 +93,7 @@ def test_create_bundle(init_setup, bundle_dir, mq_traces, ops_service, tracked_f
(acstor_namespace, "containerstorage"),
(ssc_namespace, OpsServiceType.secretstore.value),
(certmanager_namespace, OpsServiceType.certmanager.value),
(osm_namespace, OpsServiceType.openservicemesh.value),
]:
if namespace:
walk_result.pop(path.join(BASE_ZIP_PATH, namespace, service), {})
Expand Down Expand Up @@ -140,33 +142,16 @@ def _get_expected_services(
) -> List[str]:
expected_services = [ops_service] if ops_service else OpsServiceType.list()

# device registry folder will not be created if there are no device registry resources
if (
not walk_result.get(path.join(BASE_ZIP_PATH, namespace, OpsServiceType.deviceregistry.value))
and OpsServiceType.deviceregistry.value in expected_services
):
expected_services.remove(OpsServiceType.deviceregistry.value)

# arccotainerstorage folder will not be created under aio namespace
if (
not walk_result.get(path.join(BASE_ZIP_PATH, namespace, "arccontainerstorage"))
and OpsServiceType.arccontainerstorage.value in expected_services
):
expected_services.remove(OpsServiceType.arccontainerstorage.value)

# secretstore folder will not be created if there are no secretstore resources
if (
not walk_result.get(path.join(BASE_ZIP_PATH, namespace, OpsServiceType.secretstore.value))
and OpsServiceType.secretstore.value in expected_services
):
expected_services.remove(OpsServiceType.secretstore.value)

# azuremonitor folder will not be created if there are no azuremonitor resources
if (
not walk_result.get(path.join(BASE_ZIP_PATH, namespace, OpsServiceType.azuremonitor.value))
and OpsServiceType.azuremonitor.value in expected_services
):
expected_services.remove(OpsServiceType.azuremonitor.value)
# remove services that are not created in aio namespace
for monikor, service in [
(OpsServiceType.deviceregistry.value, OpsServiceType.deviceregistry.value),
("arccontainerstorage", OpsServiceType.arccontainerstorage.value),
(OpsServiceType.secretstore.value, OpsServiceType.secretstore.value),
(OpsServiceType.azuremonitor.value, OpsServiceType.azuremonitor.value),
(OpsServiceType.openservicemesh.value, OpsServiceType.openservicemesh.value),
]:
if not walk_result.get(path.join(BASE_ZIP_PATH, namespace, monikor)) and service in expected_services:
expected_services.remove(service)

expected_services.append("meta")
return expected_services
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
# coding=utf-8
# ----------------------------------------------------------------------------------------------
# Copyright (c) Microsoft Corporation. All rights reserved.
# Licensed under the MIT License. See License file in the project root for license information.
# ----------------------------------------------------------------------------------------------

from knack.log import get_logger
from azext_edge.edge.common import OpsServiceType
from azext_edge.edge.providers.edge_api import OPENSERVICEMESH_CONFIG_API_V1, OPENSERVICEMESH_POLICY_API_V1
from .helpers import (
check_custom_resource_files,
check_workload_resource_files,
get_file_map,
run_bundle_command,
)

logger = get_logger(__name__)


def test_create_bundle_osm(init_setup, tracked_files):
"""Test for ensuring file names and content. ONLY CHECKS openservicemesh."""
# dir for unpacked files
ops_service = OpsServiceType.openservicemesh.value
command = f"az iot ops support create-bundle --ops-service {ops_service}"
walk_result, bundle_path = run_bundle_command(command=command, tracked_files=tracked_files)
file_map = get_file_map(walk_result, ops_service)

# arc-osm-system
osm_file_map = file_map["osm"]

check_custom_resource_files(file_objs=osm_file_map, resource_api=OPENSERVICEMESH_CONFIG_API_V1)
check_custom_resource_files(file_objs=osm_file_map, resource_api=OPENSERVICEMESH_POLICY_API_V1)

expected_workload_types = ["configmap", "deployment", "pod", "replicaset", "service"]
expected_types = set(expected_workload_types).union(OPENSERVICEMESH_CONFIG_API_V1.kinds)
expected_types = expected_types.union(OPENSERVICEMESH_POLICY_API_V1.kinds)

assert set(osm_file_map.keys()).issubset(set(expected_types))

workload_resource_prefixes = [
"osm",
"kube-root-ca",
"preset-mesh-config",
]
check_workload_resource_files(
file_objs=osm_file_map,
expected_workload_types=expected_workload_types,
prefixes=workload_resource_prefixes,
bundle_path=bundle_path,
)
Loading

0 comments on commit 81ae30f

Please sign in to comment.