Skip to content

Commit 26dc8ca

Browse files
authored
Merge pull request #120 from phj-loopy/master
2 parents 0c51074 + c2907a5 commit 26dc8ca

File tree

4 files changed

+187
-221
lines changed

4 files changed

+187
-221
lines changed

README.md

Lines changed: 74 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ Please contact us if you need any further information.
2929
|--------------------------------------------------------------------------|-------------------------------------------------------------|
3030
| Instance | [Application Gateways](#application-gateways) |
3131
| Container | [Container Instances](#container-instances) |
32+
| Container | [Container Registries](#container-registries) |
3233
| Instance | [CosmosDB](#cosmos-db) |
3334
| Disk | [Disks](#disks) |
3435
| Instance | [KeyVaults](#key-vaults) |
@@ -49,6 +50,7 @@ Please contact us if you need any further information.
4950
| ScaleSet | [VM ScaleSets](#virtual-machine-scale-sets) |
5051
| Service | [Web PubSub Service](#web-pubsub-service) |
5152
| Score<br>OperationalExcellence<br>Performance<br>Reliability<br>Security | [Advisor](#advisor) |
53+
| Instance | [Functions](#functions) |
5254

5355

5456
---
@@ -111,6 +113,8 @@ The following is a list of services being collected and service code information
111113
| 20 | Container Instances | Microsoft.ContainerInstance/containerGroups |
112114
| 21 | Web PubSub Service | Microsoft.SignalRService/WebPubSub |
113115
| 22 | Advisor | Microsoft.Advisor/advisorScore<br>Microsoft.ResourceHealth/events |
116+
| 23 | Container Registries | Microsoft.ContainerRegistry/registries |
117+
| 24 | Functions | Microsoft.Web/sites |
114118

115119
---
116120

@@ -836,6 +840,43 @@ Deprecated)
836840
```
837841
"Microsoft.ContainerInstance/containerGroups/read"
838842
```
843+
844+
#### [Container Registries](https://learn.microsoft.com/ko-kr/python/api/azure-mgmt-containerregistry/azure.mgmt.containerregistry.containerregistrymanagementclient?view=azure-python)
845+
846+
- Container Registries
847+
- Scope
848+
- https://learn.microsoft.com/ko-kr/python/api/azure-mgmt-containerregistry/azure.mgmt.containerregistry.containerregistrymanagementclient?view=azure-python
849+
- registries
850+
- list()
851+
- get()
852+
- list_usages()
853+
- webhooks
854+
- list()
855+
- replications
856+
- list()
857+
- tasks
858+
- list()
859+
- connected_registries
860+
- list()
861+
- cache_rules
862+
- list()
863+
- tokens
864+
- list()
865+
- scope_maps
866+
- list()
867+
- Permissions
868+
```
869+
"Microsoft.ContainerRegistry/registries/read",
870+
"Microsoft.ContainerRegistry/registries/listUsages/read",
871+
"Microsoft.ContainerRegistry/registries/webhooks/read",
872+
"Microsoft.ContainerRegistry/registries/replications/read",
873+
"Microsoft.ContainerRegistry/registries/tasks/read",
874+
"Microsoft.ContainerRegistry/registries/connectedRegistries/read",
875+
"Microsoft.ContainerRegistry/registries/cacheRules/read",
876+
"Microsoft.ContainerRegistry/registries/tokens/read",
877+
"Microsoft.ContainerRegistry/registries/scopeMaps/read",
878+
"Microsoft.Resources/subscriptions/resourceGroups/read"
879+
```
839880
840881
#### [Web PubSub Service](https://learn.microsoft.com/en-us/python/api/overview/azure/web-pubsub?view=azure-python)
841882
@@ -863,6 +904,35 @@ Deprecated)
863904
- list()
864905
- Permissions
865906
907+
#### [Functions](https://learn.microsoft.com/ko-kr/python/api/azure-mgmt-web/azure.mgmt.web.websitemanagementclient?view=azure-python)
908+
909+
- Functions
910+
- Scope
911+
- https://learn.microsoft.com/ko-kr/python/api/azure-mgmt-web/azure.mgmt.web.websitemanagementclient?view=azure-python
912+
- web_apps
913+
- list()
914+
- get()
915+
- list_private_endpoint_connections()
916+
- list_hybrid_connections()
917+
- app_service_plans
918+
- get()
919+
- https://learn.microsoft.com/ko-kr/python/api/azure-mgmt-network/azure.mgmt.network.networkmanagementclient?view=azure-python
920+
- virtual_networks
921+
- get()
922+
- subnets
923+
- get()
924+
- Permissions
925+
```
926+
"Microsoft.Web/*/read",
927+
"Microsoft.Network/virtualNetworks/read",
928+
"Microsoft.Network/virtualNetworks/subnets/read",
929+
"Microsoft.Network/privateEndpoints/read",
930+
"Microsoft.Network/publicIPAddresses/read",
931+
"Microsoft.Network/natGateways/read",
932+
"Microsoft.Network/networkSecurityGroups/read",
933+
"Microsoft.Network/routeTables/read",
934+
"Microsoft.Resources/*/read"
935+
```
866936
---
867937
868938
## Options
@@ -896,7 +966,9 @@ The cloud_service_types items that can be specified are as follows.
896966
'VirtualNetworks',
897967
'VMScaleSets',
898968
'ContainerInstances',
899-
'WebPubSubService'
969+
'WebPubSubService',
970+
"ContainerRegistries",
971+
"Functions"
900972
]
901973
}
902974
</code>
@@ -962,6 +1034,7 @@ The default ASSET_URL in cloud_service_conf is
9621034
9631035
| Version | Description | Affected Service | Release Date |
9641036
|---------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|-----------------------------------------------------|--------------|
1037+
| 2.0.9 | - Add Azure Functions, Container Registries | Functions, Container Registries | 2025.12.03 |
9651038
| 2.0.8 | - Add Azure Advisor service | | |
9661039
| 2.0.5 | - Add Azure Cognitive service | | |
9671040
| 2.0.0 | - [Migration to spaceone framework 2.0](https://github.com/cloudforet-io/plugin-azure-inven-collector/issues/91) | All Services | 2024.08.22 |

src/plugin/connector/base.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@
88
from azure.mgmt.cognitiveservices import CognitiveServicesManagementClient
99
from azure.mgmt.compute import ComputeManagementClient
1010
from azure.mgmt.containerinstance import ContainerInstanceManagementClient
11-
# Container Registry 클라이언트 import 추가
1211
from azure.mgmt.containerregistry import ContainerRegistryManagementClient
1312
from azure.mgmt.cosmosdb import CosmosDBManagementClient
1413
from azure.mgmt.keyvault import KeyVaultManagementClient

src/plugin/manager/container_registries/registry_manager.py

Lines changed: 39 additions & 84 deletions
Original file line numberDiff line numberDiff line change
@@ -32,24 +32,20 @@ def create_cloud_service_type(self):
3232
)
3333

3434
def create_cloud_service(self, options, secret_data, schema):
35+
# Collect container registry resources
3536
cloud_services = []
3637
error_responses = []
3738

38-
container_registries_conn = ContainerRegistriesConnector(
39-
secret_data=secret_data
40-
)
39+
container_registries_conn = ContainerRegistriesConnector(secret_data=secret_data)
4140
subscription_conn = SubscriptionsConnector(secret_data=secret_data)
4241

43-
subscription_raw = subscription_conn.get_subscription(
44-
secret_data["subscription_id"]
45-
)
42+
# Load subscription info
43+
subscription_raw = subscription_conn.get_subscription(secret_data["subscription_id"])
4644
subscription_info = self.convert_nested_dictionary(subscription_raw)
4745

46+
# Validate subscription info
4847
if not isinstance(subscription_info, dict):
49-
_LOGGER.error(
50-
"[ContainerRegistries] invalid subscription_info. raw=%r",
51-
subscription_raw,
52-
)
48+
_LOGGER.error("[ContainerRegistries] Invalid subscription info")
5349
error_responses.append(
5450
make_error_response(
5551
error=Exception("Invalid subscription info"),
@@ -60,33 +56,25 @@ def create_cloud_service(self, options, secret_data, schema):
6056
)
6157
return cloud_services, error_responses
6258

59+
# Iterate registry list
6360
for registry in container_registries_conn.list_registries():
6461
try:
6562
registry_dict = self.convert_nested_dictionary(registry)
6663
if not isinstance(registry_dict, dict):
67-
_LOGGER.error(
68-
"[ContainerRegistries] registry list item is not dict. raw=%r",
69-
registry,
70-
)
7164
continue
7265

7366
registry_id = registry_dict["id"]
7467
resource_group_name = self.get_resource_group_from_id(registry_id)
7568
registry_name = registry_dict["name"]
7669

70+
# Fetch full registry detail
7771
registry_dict = self.convert_nested_dictionary(
78-
container_registries_conn.get_registry(
79-
resource_group_name, registry_name
80-
)
72+
container_registries_conn.get_registry(resource_group_name, registry_name)
8173
)
82-
8374
if not isinstance(registry_dict, dict):
84-
_LOGGER.error(
85-
"[ContainerRegistries] registry dict is not dict. "
86-
f"rg={resource_group_name}, name={registry_name}, raw={registry_dict}"
87-
)
8875
continue
8976

77+
# Base fields
9078
registry_dict.update(
9179
{
9280
"resource_group": resource_group_name,
@@ -96,27 +84,18 @@ def create_cloud_service(self, options, secret_data, schema):
9684
}
9785
)
9886

87+
# Populate registry data
9988
self._set_settings_info(registry_dict)
100-
101-
self._set_services_info(
102-
container_registries_conn,
103-
registry_dict,
104-
resource_group_name,
105-
registry_name,
106-
)
107-
89+
self._set_services_info(container_registries_conn, registry_dict, resource_group_name, registry_name)
10890
self._set_repository_permissions_info(
109-
container_registries_conn,
110-
registry_dict,
111-
resource_group_name,
112-
registry_name,
91+
container_registries_conn, registry_dict, resource_group_name, registry_name
11392
)
11493

115-
registry_dict = self.update_tenant_id_from_secret_data(
116-
registry_dict, secret_data
117-
)
94+
# Common metadata
95+
registry_dict = self.update_tenant_id_from_secret_data(registry_dict, secret_data)
11896
self.set_region_code(registry_dict["location"])
11997

98+
# Build CloudService
12099
cloud_services.append(
121100
make_cloud_service(
122101
name=registry_dict["name"],
@@ -131,11 +110,9 @@ def create_cloud_service(self, options, secret_data, schema):
131110
data_format="dict",
132111
)
133112
)
113+
134114
except Exception as e:
135-
_LOGGER.error(
136-
f"[create_cloud_service] Error {self.service_code} {e}",
137-
exc_info=True,
138-
)
115+
_LOGGER.error(f"[create_cloud_service] Error {self.service_code}: {e}", exc_info=True)
139116
error_responses.append(
140117
make_error_response(
141118
error=e,
@@ -148,20 +125,17 @@ def create_cloud_service(self, options, secret_data, schema):
148125
return cloud_services, error_responses
149126

150127
def _set_settings_info(self, registry_dict):
128+
# Populate Settings category
151129
if not isinstance(registry_dict, dict):
152-
_LOGGER.error(
153-
"[ContainerRegistries] _set_settings_info called with non-dict: %r",
154-
registry_dict,
155-
)
156130
return
157131

158-
registry_dict["admin_user_enabled"] = registry_dict.get(
159-
"admin_user_enabled", False
160-
)
132+
registry_dict["admin_user_enabled"] = registry_dict.get("admin_user_enabled", False)
161133

134+
# Identity mapping
162135
identities = []
163136
if identity_info := registry_dict.get("identity"):
164137
identity_type = identity_info.get("type", "None")
138+
165139
if "SystemAssigned" in identity_type:
166140
identities.append(
167141
{
@@ -173,8 +147,8 @@ def _set_settings_info(self, registry_dict):
173147
)
174148

175149
for ua_id in identity_info.get("user_assigned_identities", {}):
176-
try:
177-
parts = ua_id.split("/")
150+
parts = ua_id.split("/")
151+
if len(parts) >= 5:
178152
identities.append(
179153
{
180154
"name": parts[-1],
@@ -183,42 +157,33 @@ def _set_settings_info(self, registry_dict):
183157
"subscription_id": parts[2],
184158
}
185159
)
186-
except Exception:
160+
else:
187161
identities.append({"name": ua_id, "type": "UserAssigned"})
188162
registry_dict["identities"] = identities
189163

190-
registry_dict["private_endpoints"] = [] # Placeholder
191-
164+
# Policies
192165
policies = registry_dict.get("policies", {})
193-
registry_dict["domain_name_label_scope"] = policies.get(
194-
"quarantine_policy", {}
195-
).get("status", "Unsecured")
166+
registry_dict["domain_name_label_scope"] = policies.get("quarantine_policy", {}).get("status", "Unsecured")
196167
registry_dict["soft_delete_enabled"] = (
197168
policies.get("retention_policy", {}).get("status", "disabled") == "enabled"
198169
)
199170
registry_dict.setdefault("role_assignment_mode", "RBAC_REGISTRY")
200171

201-
registry_dict["locks"] = [] # Placeholder
172+
registry_dict["private_endpoints"] = []
173+
registry_dict["locks"] = []
202174

203175
def _set_services_info(self, conn, registry_dict, rg, name):
176+
# Populate Services category
204177
if not isinstance(registry_dict, dict):
205-
_LOGGER.error(
206-
"[ContainerRegistries] _set_services_info called with non-dict: %r",
207-
registry_dict,
208-
)
209178
return
210179

211180
registry_dict["repositories"] = []
212181

213182
webhooks = conn.list_webhooks(rg, name)
214-
registry_dict["webhooks"] = [
215-
self.convert_nested_dictionary(w) for w in webhooks
216-
]
183+
registry_dict["webhooks"] = [self.convert_nested_dictionary(w) for w in webhooks]
217184

218185
replications = conn.list_replications(rg, name)
219-
registry_dict["replications"] = [
220-
self.convert_nested_dictionary(r) for r in replications
221-
]
186+
registry_dict["replications"] = [self.convert_nested_dictionary(r) for r in replications]
222187

223188
tasks = conn.list_tasks(rg, name)
224189
registry_dict["tasks"] = [self.convert_nested_dictionary(t) for t in tasks]
@@ -229,38 +194,28 @@ def _set_services_info(self, conn, registry_dict, rg, name):
229194
]
230195

231196
cache_rules = conn.list_cache_rules(rg, name)
232-
registry_dict["cache_rules"] = [
233-
self.convert_nested_dictionary(rule) for rule in cache_rules
234-
]
197+
registry_dict["cache_rules"] = [self.convert_nested_dictionary(rule) for rule in cache_rules]
235198
registry_dict["cache_credentials"] = []
236199

237200
def _set_repository_permissions_info(self, conn, registry_dict, rg, name):
201+
# Populate Repository Permissions category
238202
if not isinstance(registry_dict, dict):
239-
_LOGGER.error(
240-
"[ContainerRegistries] _set_repository_permissions_info called with non-dict: %r",
241-
registry_dict,
242-
)
243203
return
244204

245205
tokens = conn.list_tokens(rg, name)
246206
token_list = []
247207
for t in tokens:
248208
td = self.convert_nested_dictionary(t)
249-
250209
if not isinstance(td, dict):
251-
_LOGGER.error(
252-
"[ContainerRegistries] token item is not dict. raw=%r",
253-
t,
254-
)
255210
continue
256211

257-
if creds := td.get("credentials"):
212+
creds = td.get("credentials")
213+
if creds:
258214
td["password1_expiry"] = creds.get("password1", {}).get("expiry")
259215
td["password2_expiry"] = creds.get("password2", {}).get("expiry")
216+
260217
token_list.append(td)
261-
registry_dict["tokens"] = token_list
262218

219+
registry_dict["tokens"] = token_list
263220
scope_maps = conn.list_scope_maps(rg, name)
264-
registry_dict["scope_maps"] = [
265-
self.convert_nested_dictionary(s) for s in scope_maps
266-
]
221+
registry_dict["scope_maps"] = [self.convert_nested_dictionary(s) for s in scope_maps]

0 commit comments

Comments
 (0)