Skip to content

Commit fdaeb53

Browse files
authored
[azure][feat] Monitoring and KeyVault resources (#2156)
1 parent f692309 commit fdaeb53

31 files changed

+3260
-120
lines changed

fixlib/fixlib/json_bender.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -622,3 +622,7 @@ def bend_with_context(inner: Mapping, transport: Transport) -> Any:
622622

623623
context = {} if context is None else context
624624
return bend_with_context(mapping, Transport(source, context))
625+
626+
627+
Lower = F(lambda s: s.lower() if isinstance(s, str) else s)
628+
Upper = F(lambda s: s.upper() if isinstance(s, str) else s)

plugins/azure/fix_plugin_azure/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -132,7 +132,7 @@ def list_all(resource: Type[T], config: AzureConfig, credentials: AzureCredentia
132132
if resource.api_spec is None:
133133
return []
134134
client = MicrosoftClient.create(config, credentials, "global")
135-
return [resource.from_api(js) for js in client.list(resource.api_spec)]
135+
return [rs for js in client.list(resource.api_spec) if (rs := resource.from_api(js))]
136136

137137

138138
def collect_account_proxy(collector_arg: AzureCollectorArg, queue: multiprocessing.Queue) -> None: # type: ignore

plugins/azure/fix_plugin_azure/collector.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,13 +28,15 @@
2828
resources as graph_resources,
2929
MicrosoftGraphOrganizationRoot,
3030
)
31+
from fix_plugin_azure.resource.monitor import resources as monitor_resources
3132
from fix_plugin_azure.resource.network import (
3233
AzureExpressRoutePortsLocation,
3334
AzureNetworkVirtualApplianceSku,
3435
AzureNetworkUsage,
3536
resources as network_resources,
3637
)
3738
from fix_plugin_azure.resource.mysql import AzureMysqlServerType, resources as mysql_resources
39+
from fix_plugin_azure.resource.keyvault import resources as keyvault_resources
3840
from fix_plugin_azure.resource.sql_server import resources as sql_resources
3941
from fix_plugin_azure.resource.postgresql import (
4042
AzurePostgresqlServerType,
@@ -68,6 +70,8 @@ def resource_with_params(clazz: Type[MicrosoftResource], param: str) -> bool:
6870
+ sql_resources
6971
+ mysql_resources
7072
+ postgresql_resources
73+
+ monitor_resources
74+
+ keyvault_resources
7175
)
7276
all_resources = subscription_resources + graph_resources # defines all resource kinds. used in model check
7377

plugins/azure/fix_plugin_azure/resource/base.py

Lines changed: 40 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ def get_client(subscription_id: str) -> MicrosoftClient:
5252

5353

5454
def parse_json(
55-
json: Json, clazz: Type[T], builder: GraphBuilder, mapping: Optional[Dict[str, Bender]] = None
55+
json: Json, clazz: Type[T], builder: Optional[GraphBuilder] = None, mapping: Optional[Dict[str, Bender]] = None
5656
) -> Optional[T]:
5757
"""
5858
Use this method to parse json into a class. If the json can not be parsed, the error is reported to the core.
@@ -67,14 +67,19 @@ def parse_json(
6767
mapped = bend(mapping, json) if mapping is not None else json
6868
return from_json(mapped, clazz)
6969
except Exception as e:
70-
# report and log the error
71-
builder.core_feedback.error(f"Failed to parse json into {clazz.__name__}: {e}. Source: {json}", log)
72-
# based on the strict flag, either raise the exception or return None
73-
if builder.config.discard_account_on_resource_error:
74-
raise
70+
message = f"Failed to parse json into {clazz.__name__}: {e}. Source: {json}"
71+
if builder:
72+
# report and log the error
73+
builder.core_feedback.error(message, log)
74+
# based on the strict flag, either raise the exception or return None
75+
if builder.config.discard_account_on_resource_error:
76+
raise
77+
else:
78+
log.warning(message)
7579
return None
7680

7781

82+
@define(eq=False, slots=False)
7883
class MicrosoftResource(BaseResource):
7984
kind: ClassVar[str] = "microsoft_resource"
8085
# The mapping to transform the incoming API json into the internal representation.
@@ -224,19 +229,20 @@ def collect(
224229
result: List[MicrosoftResourceType] = []
225230
for js in raw:
226231
# map from api
227-
instance = cls.from_api(js)
228-
instance.pre_process(builder, js)
229-
# add to graph
230-
if (added := builder.add_node(instance, js)) is not None:
231-
# post process
232-
added.post_process(builder, js)
233-
result.append(added)
232+
if instance := cls.from_api(js, builder):
233+
instance.pre_process(builder, js)
234+
# add to graph
235+
if (added := builder.add_node(instance, js)) is not None:
236+
# post process
237+
added.post_process(builder, js)
238+
result.append(added)
234239
return result
235240

236241
@classmethod
237-
def from_api(cls: Type[MicrosoftResourceType], json: Json) -> MicrosoftResourceType:
238-
mapped = bend(cls.mapping, json)
239-
return cls.from_json(mapped)
242+
def from_api(
243+
cls: Type[MicrosoftResourceType], json: Json, builder: Optional[GraphBuilder] = None
244+
) -> Optional[MicrosoftResourceType]:
245+
return parse_json(json, cls, builder, cls.mapping)
240246

241247
@classmethod
242248
def called_collect_apis(cls) -> List[MicrosoftRestSpec]:
@@ -504,21 +510,6 @@ class AzurePrincipalClient:
504510
principal_id: Optional[str] = field(default=None, metadata={'description': 'The principal id of user assigned identity.'}) # fmt: skip
505511

506512

507-
@define(eq=False, slots=False)
508-
class AzureManagedServiceIdentity:
509-
kind: ClassVar[str] = "azure_managed_service_identity"
510-
mapping: ClassVar[Dict[str, Bender]] = {
511-
"principal_id": S("principalId"),
512-
"tenant_id": S("tenantId"),
513-
"type": S("type"),
514-
"user_assigned_identities": S("userAssignedIdentities"),
515-
}
516-
principal_id: Optional[str] = field(default=None, metadata={'description': 'The principal id of the system assigned identity. This property will only be provided for a system assigned identity.'}) # fmt: skip
517-
tenant_id: Optional[str] = field(default=None, metadata={'description': 'The tenant id of the system assigned identity. This property will only be provided for a system assigned identity.'}) # fmt: skip
518-
type: Optional[str] = field(default=None, metadata={'description': 'The type of identity used for the resource. The type SystemAssigned, UserAssigned includes both an implicitly created identity and a set of user assigned identities. The type None will remove any identities from the virtual machine.'}) # fmt: skip
519-
user_assigned_identities: Optional[Dict[str, AzurePrincipalClient]] = field(default=None, metadata={'description': 'The list of user identities associated with resource. The user identity dictionary key references will be ARM resource ids in the form: /subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.ManagedIdentity/userAssignedIdentities/{identityName} .'}) # fmt: skip
520-
521-
522513
@define(eq=False, slots=False)
523514
class AzurePrivateLinkServiceConnectionState:
524515
kind: ClassVar[str] = "azure_private_link_service_connection_state"
@@ -561,6 +552,7 @@ class AzureSubscription(MicrosoftResource, BaseAccount):
561552
"id": S("subscriptionId"),
562553
"tags": S("tags", default={}),
563554
"authorization_source": S("authorizationSource"),
555+
"name": S("displayName"),
564556
"display_name": S("displayName"),
565557
"managed_by_tenants": S("managedByTenants", default=[]) >> ForallBend(S("tenantId")),
566558
"state": S("state"),
@@ -636,6 +628,23 @@ class AzureProxyResource:
636628
type: Optional[str] = field(default=None, metadata={'description': 'The type of the resource. E.g. Microsoft.Compute/virtualMachines or Microsoft.Storage/storageAccounts '}) # fmt: skip
637629

638630

631+
@define(eq=False, slots=False)
632+
class AzureIdentity:
633+
kind: ClassVar[str] = "azure_identity"
634+
mapping: ClassVar[Dict[str, Bender]] = {
635+
"client_id": S("clientId"),
636+
"principal_id": S("principalId"),
637+
"tenant_id": S("tenantId"),
638+
"type": S("type"),
639+
"user_assigned_identities": S("userAssignedIdentities"),
640+
}
641+
client_id: Optional[str] = field(default=None, metadata={'description': 'The client id of user assigned identity.'}) # fmt: skip
642+
principal_id: Optional[str] = field(default=None, metadata={'description': 'The principal ID of resource identity.'}) # fmt: skip
643+
tenant_id: Optional[str] = field(default=None, metadata={"description": "The tenant ID of resource."})
644+
type: Optional[str] = field(default=None, metadata={"description": "Type of managed service identity."})
645+
user_assigned_identities: Optional[Dict[str, AzureUserAssignedIdentity]] = field(default=None, metadata={'description': 'The list of user identities associated with the resource. The user identity dictionary key references will be ARM resource ids in the form: /subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.ManagedIdentity/userAssignedIdentities/{identityName} .'}) # fmt: skip
646+
647+
639648
@define(eq=False, slots=False)
640649
class AzureSku:
641650
kind: ClassVar[str] = "azure_sku"

plugins/azure/fix_plugin_azure/resource/containerservice.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
AzureExtendedLocation,
1313
AzureUserAssignedIdentity,
1414
AzurePrincipalClient,
15-
AzureManagedServiceIdentity,
15+
AzureIdentity,
1616
)
1717
from fixlib.baseresources import BaseManagedKubernetesClusterProvider, BaseSnapshot, EdgeType, ModelReference
1818
from fixlib.json_bender import Bender, S, Bend, ForallBend
@@ -86,12 +86,12 @@ class AzureFleet(MicrosoftResource):
8686
"e_tag": S("eTag"),
8787
"resource_group": S("resourceGroup"),
8888
"hub_profile": S("properties", "hubProfile") >> Bend(AzureFleetHubProfile.mapping),
89-
"azure_fleet_identity": S("identity") >> Bend(AzureManagedServiceIdentity.mapping),
89+
"azure_fleet_identity": S("identity") >> Bend(AzureIdentity.mapping),
9090
"provisioning_state": S("properties", "provisioningState"),
9191
}
9292
e_tag: Optional[str] = field(default=None, metadata={'description': 'If eTag is provided in the response body, it may also be provided as a header per the normal etag convention. Entity tags are used for comparing two or more entities from the same requested resource. HTTP/1.1 uses entity tags in the etag (section 14.19), If-Match (section 14.24), If-None-Match (section 14.26), and If-Range (section 14.27) header fields.'}) # fmt: skip
9393
hub_profile: Optional[AzureFleetHubProfile] = field(default=None, metadata={'description': 'The FleetHubProfile configures the fleet hub.'}) # fmt: skip
94-
azure_fleet_identity: Optional[AzureManagedServiceIdentity] = field(default=None, metadata={'description': 'Managed service identity (system assigned and/or user assigned identities)'}) # fmt: skip
94+
azure_fleet_identity: Optional[AzureIdentity] = field(default=None, metadata={'description': 'Managed service identity (system assigned and/or user assigned identities)'}) # fmt: skip
9595
resource_group: Optional[str] = field(default=None, metadata={"description": "Resource group name"})
9696
_cluster_resource_ids: Optional[List[str]] = field(
9797
default=None, metadata={"description": "Reference to the cluster IDs"}

0 commit comments

Comments
 (0)