Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

refactor: init responsible for foundation layer only. UX enhancements. #346

Merged
merged 4 commits into from
Sep 10, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
71 changes: 47 additions & 24 deletions azext_edge/edge/_help.py
Original file line number Diff line number Diff line change
Expand Up @@ -448,23 +448,58 @@ def load_iotops_help():
"iot ops init"
] = """
type: command
short-summary: Bootstrap, configure and deploy IoT Operations to the target Arc-enabled cluster.
short-summary: Bootstrap the target Arc-enabled cluster for IoT Operations deployment.
long-summary: |
For additional resources including how to Arc-enable a cluster see
https://learn.microsoft.com/en-us/azure/iot-operations/deploy-iot-ops/howto-prepare-cluster
An Arc-enabled cluster is required to deploy IoT Operations. See the following resource for
more info https://aka.ms/aziotops-arcconnect.

IoT Operations depends on a service principal (SP) for Key Vault CSI driver secret synchronization.
The init operation will do work in installing and configuring a foundation layer of edge
services necessary for IoT Operations deployment.

By default, init will do work in creating and configuring a suitable app registration
via Microsoft Graph then apply it to the cluster.
After the foundation layer has been installed the `az iot ops create` command should
be used to deploy an instance.
examples:
- name: Usage with minimum input. This form will deploy the IoT Operations foundation layer.
text: >
az iot ops init --cluster mycluster -g myresourcegroup --sr-resource-id $SCHEMA_REGISTRY_RESOURCE_ID
- name: Similar to the prior example but with Arc Container Storage fault-tolerance enabled (requires at least 3 nodes).
text: >
az iot ops init --cluster mycluster -g myresourcegroup --sr-resource-id $SCHEMA_REGISTRY_RESOURCE_ID
--enable-fault-tolerance
"""

helps[
"iot ops create"
] = """
type: command
short-summary: Create an IoT Operations instance.
long-summary: |
A succesful execution of init is required before running this command.

You can short-circuit this work, by pre-creating an app registration, then providing values
for --sp-app-id, --sp-object-id and --sp-secret. By providing the SP fields, no additional
work via Microsoft Graph operations will be done.
The result of the command nets an IoT Operations instance with
a set of default resources configured for cohesive function.

Pre-creating an app registration is useful when the logged-in principal has constrained
Entra Id permissions. For example in CI/automation scenarios, or an orgs separation of user
responsibility.
examples:
- name: Create the target instance with minimum input.
text: >
az iot ops create --cluster mycluster -g myresourcegroup --name myinstance
- name: The following example adds customization to the default broker instance resource
as well as an instance description and tags.
text: >
az iot ops create --cluster mycluster -g myresourcegroup --name myinstance
--broker-mem-profile High --broker-backend-workers 4 --description 'Contoso Factory'
--tags tier=testX1
- name: This example shows deploying an additional insecure (no authn or authz) broker listener
configured for port 1883 of service type load balancer. Useful for testing and/or demos.
Do not use the insecure option in production.
text: >
az iot ops create --cluster mycluster -g myresourcegroup --name myinstance
--add-insecure-listener
- name: This form shows how to disable resource sync rules from the instance deployment,
which may be necessary due to lack of permissions to deploy them.
text: >
az iot ops create --cluster mycluster -g myresourcegroup --name myinstance
--disable-rsync-rules
"""

helps[
Expand Down Expand Up @@ -545,18 +580,6 @@ def load_iotops_help():
az iot ops update --name myinstance -g myresourcegroup --desc "Fabrikam Widget Factory B42"
"""

helps[
"iot ops create"
] = """
type: command
short-summary: Create an IoT Operations instance.

examples:
- name: Create the target instance with minimum input.
text: >
az iot ops create --name myinstance --cluster mycluster -g myresourcegroup
"""

helps[
"iot ops asset"
] = """
Expand Down
47 changes: 0 additions & 47 deletions azext_edge/edge/commands_edge.py
Original file line number Diff line number Diff line change
Expand Up @@ -109,29 +109,11 @@ def init(
cluster_name: str,
resource_group_name: str,
schema_registry_resource_id: str,
cluster_namespace: str = DEFAULT_NAMESPACE,
location: Optional[str] = None,
custom_location_name: Optional[str] = None,
disable_rsync_rules: Optional[bool] = None,
instance_name: Optional[str] = None,
instance_description: Optional[str] = None,
dataflow_profile_instances: int = 1,
container_runtime_socket: Optional[str] = None,
kubernetes_distro: str = KubernetesDistroType.k8s.value,
trust_source: str = TrustSourceType.self_signed.value,
enable_fault_tolerance: Optional[bool] = None,
ops_config: Optional[List[str]] = None,
mi_user_assigned_identities: Optional[List[str]] = None,
# Broker
custom_broker_config_file: Optional[str] = None,
broker_memory_profile: str = MqMemoryProfile.medium.value,
broker_service_type: str = MqServiceType.cluster_ip.value,
broker_backend_partitions: int = 2,
broker_backend_workers: int = 2,
broker_backend_redundancy_factor: int = 2,
broker_frontend_workers: int = 2,
broker_frontend_replicas: int = 2,
add_insecure_listener: Optional[bool] = None,
no_progress: Optional[bool] = None,
ensure_latest: Optional[bool] = None,
**kwargs,
Expand All @@ -140,51 +122,22 @@ def init(
from .providers.orchestration import WorkManager
from .util import (
is_env_flag_enabled,
read_file_content,
)

no_pre_flight = is_env_flag_enabled(INIT_NO_PREFLIGHT_ENV_KEY)

# TODO - @digimaun
custom_broker_config = None
if custom_broker_config_file:
custom_broker_config = json.loads(read_file_content(file_path=custom_broker_config_file))

if broker_service_type == MqServiceType.load_balancer.value and add_insecure_listener:
raise ArgumentUsageError(
f"--add-insecure-listener cannot be used when --broker-service-type is {MqServiceType.load_balancer.value}."
)

work_manager = WorkManager(cmd)
return work_manager.execute_ops_init(
show_progress=not no_progress,
pre_flight=not no_pre_flight,
cluster_name=cluster_name,
resource_group_name=resource_group_name,
cluster_namespace=cluster_namespace,
location=location,
custom_location_name=custom_location_name,
disable_rsync_rules=disable_rsync_rules,
instance_name=instance_name,
instance_description=instance_description,
add_insecure_listener=add_insecure_listener,
dataflow_profile_instances=dataflow_profile_instances,
container_runtime_socket=container_runtime_socket,
kubernetes_distro=kubernetes_distro,
enable_fault_tolerance=enable_fault_tolerance,
ops_config=ops_config,
trust_source=trust_source,
schema_registry_resource_id=schema_registry_resource_id,
mi_user_assigned_identities=mi_user_assigned_identities,
# Broker
custom_broker_config=custom_broker_config,
broker_memory_profile=broker_memory_profile,
broker_service_type=broker_service_type,
broker_backend_partitions=broker_backend_partitions,
broker_backend_workers=broker_backend_workers,
broker_backend_redundancy_factor=broker_backend_redundancy_factor,
broker_frontend_workers=broker_frontend_workers,
broker_frontend_replicas=broker_frontend_replicas,
)


Expand Down
1 change: 1 addition & 0 deletions azext_edge/edge/providers/orchestration/common.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@

AIO_INSECURE_LISTENER_NAME = "default-insecure"
AIO_INSECURE_LISTENER_SERVICE_NAME = "aio-broker-insecure"
AIO_INSECURE_LISTENER_SERVICE_PORT = 1883


class MqMode(Enum):
Expand Down
70 changes: 69 additions & 1 deletion azext_edge/edge/providers/orchestration/targets.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,15 @@
)
from ...util import assemble_nargs_to_dict
from ...util.az_client import parse_resource_id
from ..orchestration.common import (
AIO_INSECURE_LISTENER_NAME,
AIO_INSECURE_LISTENER_SERVICE_NAME,
AIO_INSECURE_LISTENER_SERVICE_PORT,
MqServiceType,
)
from .common import KubernetesDistroType, TrustSourceType
from .template import (
IOT_OPERATIONS_VERSION_MONIKER,
M2_ENABLEMENT_TEMPLATE,
M2_INSTANCE_TEMPLATE,
TemplateBlueprint,
Expand Down Expand Up @@ -64,7 +71,8 @@ def __init__(
self.safe_cluster_name = self._sanitize_k8s_name(self.cluster_name)
self.resource_group_name = resource_group_name
# TODO - @digimaun
parse_resource_id(schema_registry_resource_id)
if schema_registry_resource_id:
parse_resource_id(schema_registry_resource_id)
self.schema_registry_resource_id = schema_registry_resource_id
self.cluster_namespace = self._sanitize_k8s_name(cluster_namespace)
self.location = location
Expand Down Expand Up @@ -123,6 +131,21 @@ def _handle_apply_targets(

return template_copy, deploy_params

@property
def iot_operations_version(self):
return IOT_OPERATIONS_VERSION_MONIKER

def get_extension_versions(self, in_display_format: bool = False) -> dict:
# Don't need a deep copy here.
version_map = M2_ENABLEMENT_TEMPLATE.content["variables"]["VERSIONS"].copy()
if not in_display_format:
return version_map

display_desc = "[dim]"
for ver in version_map:
display_desc += f"• {ver}: {version_map[ver]}\n"
return display_desc[:-1] + ""

def get_ops_enablement_template(
self,
) -> Tuple[dict, dict]:
Expand Down Expand Up @@ -261,3 +284,48 @@ def get_broker_config_target_map(self):
raise InvalidArgumentValueError("\n".join(validation_errors))

return processed_config_map

# TODO - @digimaun
def get_instance_kpis(self) -> dict:
default_listener_port: int = M2_INSTANCE_TEMPLATE.content["variables"]["MQTT_SETTINGS"]["brokerListenerPort"]
default_listener_service_name: str = M2_INSTANCE_TEMPLATE.content["variables"]["MQTT_SETTINGS"][
"brokerListenerServiceName"
]

instance_kpis = {
"instance": {
"name": self.instance_name,
"description": self.instance_description,
"resourceSync": {"enabled": self.deploy_resource_sync_rules},
"location": self.location,
"broker": {
DEFAULT_BROKER: {
"listener": {
DEFAULT_BROKER_LISTENER: {
"port": default_listener_port,
"serviceName": default_listener_service_name,
"serviceType": self.broker_service_type,
}
},
},
"authn": {DEFAULT_BROKER_AUTHN: {}},
},
"dataflows": {
"profile": {DEFAULT_DATAFLOW_PROFILE: {"instanceCount": self.dataflow_profile_instances}},
"endpoint": {DEFAULT_DATAFLOW_ENDPOINT: {}},
},
}
}
if self.add_insecure_listener:
instance_kpis["instance"]["listener"][AIO_INSECURE_LISTENER_NAME] = {
"port": AIO_INSECURE_LISTENER_SERVICE_PORT,
"serviceName": AIO_INSECURE_LISTENER_SERVICE_NAME,
"serviceType": MqServiceType.load_balancer.value,
}

return instance_kpis

def get_enablement_kpis(self) -> dict:
enablement_kpis = {}

return enablement_kpis
13 changes: 4 additions & 9 deletions azext_edge/edge/providers/orchestration/template.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,18 +10,14 @@
from .common import (
AIO_INSECURE_LISTENER_NAME,
AIO_INSECURE_LISTENER_SERVICE_NAME,
AIO_INSECURE_LISTENER_SERVICE_PORT,
MqServiceType,
)


class TemplateBlueprint(NamedTuple):
commit_id: str
content: Dict[str, Any]
moniker: str

def get_component_vers(self) -> dict:
# Don't need a deep copy here.
return self.content["variables"]["VERSIONS"].copy()

def get_type_definition(self, key: str) -> Optional[dict]:
return self.content["definitions"].get(key, {"properties": {}})
Expand All @@ -47,14 +43,14 @@ def add_resource(self, resource_key: str, resource_def: dict):
def copy(self) -> "TemplateBlueprint":
return TemplateBlueprint(
commit_id=self.commit_id,
moniker=self.moniker,
content=deepcopy(self.content),
)


IOT_OPERATIONS_VERSION_MONIKER = "v0.7.0-preview"

M2_ENABLEMENT_TEMPLATE = TemplateBlueprint(
commit_id="dec7ce40c138904c3cdfd593e27ddeaebfedf171",
moniker="v0.7.0-preview.enablement",
content={
"$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
"languageVersion": "2.0",
Expand Down Expand Up @@ -421,7 +417,6 @@ def copy(self) -> "TemplateBlueprint":

M2_INSTANCE_TEMPLATE = TemplateBlueprint(
commit_id="dec7ce40c138904c3cdfd593e27ddeaebfedf171",
moniker="v0.6.0-preview",
content={
"$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
"languageVersion": "2.0",
Expand Down Expand Up @@ -831,7 +826,7 @@ def get_insecure_listener(instance_name: str, broker_name: str) -> dict:
"serviceName": AIO_INSECURE_LISTENER_SERVICE_NAME,
"ports": [
{
"port": 1883,
"port": AIO_INSECURE_LISTENER_SERVICE_PORT,
}
],
},
Expand Down
Loading