Skip to content

Commit

Permalink
Add Managed Identity to iothub (ansible-collections#1615)
Browse files Browse the repository at this point in the history
  • Loading branch information
p3ck committed Jul 3, 2024
1 parent bee4121 commit 8d25ffe
Show file tree
Hide file tree
Showing 4 changed files with 196 additions and 6 deletions.
2 changes: 1 addition & 1 deletion plugins/module_utils/azure_rm_common.py
Original file line number Diff line number Diff line change
Expand Up @@ -1327,7 +1327,7 @@ def IoThub_client(self):
self.log('Getting iothub client')
if not self._IoThub_client:
self._IoThub_client = self.get_mgmt_svc_client(IotHubClient,
api_version='2018-04-01',
api_version='2023-06-30-preview',
base_url=self._cloud_environment.endpoints.resource_manager)
return self._IoThub_client

Expand Down
102 changes: 97 additions & 5 deletions plugins/modules/azure_rm_iothub.py
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,41 @@
description:
- File upload notifications are enabled if set to C(True).
type: bool
identity:
description:
- Identity for this resource.
type: dict
version_added: '2.6.0'
suboptions:
type:
description:
- Type of the managed identity
choices:
- SystemAssigned
- UserAssigned
- 'None'
default: 'None'
type: str
user_assigned_identities:
description:
- User Assigned Managed Identities and its options
required: false
type: dict
default: {}
suboptions:
id:
description:
- List of the user assigned IDs associated to this resource
required: false
type: list
elements: str
default: []
append:
description:
- If the list of identities has to be appended to current identities (true) or if it has to replace current identities (false)
required: false
type: bool
default: True
ip_filters:
description:
- Configure rules for rejecting or accepting traffic from specific IPv4 addresses.
Expand Down Expand Up @@ -507,10 +542,17 @@
sample: "true"
''' # NOQA

from ansible_collections.azure.azcollection.plugins.module_utils.azure_rm_common import AzureRMModuleBase
from ansible_collections.azure.azcollection.plugins.module_utils.azure_rm_common_ext import AzureRMModuleBaseExt
from ansible.module_utils.common.dict_transformations import _snake_to_camel, _camel_to_snake
import re

try:
from ansible_collections.azure.azcollection.plugins.module_utils.azure_rm_common_ext import AzureRMModuleBaseExt
from azure.mgmt.iothub import models as IotHubModels
except ImportError:
# This is handled in azure_rm_common
pass


ip_filter_spec = dict(
name=dict(type='str', required=True),
Expand Down Expand Up @@ -553,7 +595,36 @@
)


class AzureRMIoTHub(AzureRMModuleBase):
user_assigned_identities_spec = dict(
id=dict(
type='list',
default=[],
elements='str'
),
append=dict(
type='bool',
default=True
)
)


managed_identity_spec = dict(
type=dict(
type='str',
choices=['SystemAssigned',
'UserAssigned',
'None'],
default='None'
),
user_assigned_identities=dict(
type='dict',
options=user_assigned_identities_spec,
default={}
),
)


class AzureRMIoTHub(AzureRMModuleBaseExt):

def __init__(self):

Expand All @@ -568,7 +639,11 @@ def __init__(self):
enable_file_upload_notifications=dict(type='bool'),
ip_filters=dict(type='list', elements='dict', options=ip_filter_spec),
routing_endpoints=dict(type='list', elements='dict', options=routing_endpoints_spec),
routes=dict(type='list', elements='dict', options=routes_spec)
routes=dict(type='list', elements='dict', options=routes_spec),
identity=dict(
type='dict',
options=managed_identity_spec
),
)

self.results = dict(
Expand All @@ -588,9 +663,18 @@ def __init__(self):
self.ip_filters = None
self.routing_endpoints = None
self.routes = None
self._managed_identity = None

super(AzureRMIoTHub, self).__init__(self.module_arg_spec, supports_check_mode=True)

@property
def managed_identity(self):
if not self._managed_identity:
self._managed_identity = {"identity": IotHubModels.ArmIdentity,
"user_assigned": IotHubModels.ManagedIdentity
}
return self._managed_identity

def exec_module(self, **kwargs):

for key in list(self.module_arg_spec.keys()) + ['tags']:
Expand Down Expand Up @@ -629,10 +713,12 @@ def exec_module(self, **kwargs):
routing_property = self.IoThub_models.RoutingProperties(endpoints=routing_endpoints,
routes=routes)
iothub_property.routing = routing_property
identities_changed, updated_identities = self.update_identities()
iothub = self.IoThub_models.IotHubDescription(location=self.location,
sku=self.IoThub_models.IotHubSkuInfo(name=self.sku, capacity=self.unit),
properties=iothub_property,
tags=self.tags)
tags=self.tags,
identity=updated_identities)
if not self.check_mode:
iothub = self.create_or_update_hub(iothub)
else:
Expand Down Expand Up @@ -713,7 +799,12 @@ def exec_module(self, **kwargs):
# compare tags
tag_changed, updated_tags = self.update_tags(iothub.tags)
iothub.tags = updated_tags
if changed and not self.check_mode:

# compare identity
identity_changed, iothub.identity = self.update_identities(iothub.identity.as_dict())

if (changed or identity_changed) and not self.check_mode:
changed = True
iothub = self.create_or_update_hub(iothub)
# only tags changed
if not changed and tag_changed:
Expand Down Expand Up @@ -875,6 +966,7 @@ def to_dict(self, hub):
result['fallback_route'] = self.route_to_dict(properties.routing.fallback_route)
result['status'] = properties.state
result['storage_endpoints'] = self.instance_dict_to_dict(properties.storage_endpoints)
result['identity'] = hub.identity.as_dict() if hub.identity else None
return result


Expand Down
25 changes: 25 additions & 0 deletions plugins/modules/azure_rm_iothub_info.py
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,30 @@
type: str
returned: always
sample: f1
identity:
description:
- Identity for the Server.
type: complex
returned: when available
contains:
type:
description:
- Type of the managed identity
returned: always
sample: UserAssigned
type: str
user_assigned_identities:
description:
- User Assigned Managed Identities and its options
returned: always
type: complex
contains:
id:
description:
- Dict of the user assigned identities IDs associated to the Resource
returned: always
type: dict
elements: dict
cloud_to_device:
description:
- Cloud to device message properties.
Expand Down Expand Up @@ -574,6 +598,7 @@ def to_dict(self, hub):
result['tags'] = hub.tags
result['unit'] = hub.sku.capacity
result['sku'] = hub.sku.name.lower()
result['identity'] = hub.identity.as_dict() if hub.identity else None
result['cloud_to_device'] = dict(
max_delivery_count=properties.cloud_to_device.feedback.max_delivery_count,
ttl_as_iso8601=str(properties.cloud_to_device.feedback.ttl_as_iso8601)
Expand Down
73 changes: 73 additions & 0 deletions tests/integration/targets/azure_rm_iothub/tasks/main.yml
Original file line number Diff line number Diff line change
@@ -1,6 +1,31 @@
- name: Gather Resource Group info
azure.azcollection.azure_rm_resourcegroup_info:
name: "{{ resource_group }}"
register: __rg_info

- name: Set variables
ansible.builtin.set_fact:
rpfx: "{{ resource_group | hash('md5') | truncate(8, True, '') }}"
location: "{{ __rg_info.resourcegroups.0.location }}"

- name: Create User Managed Identities
azure_rm_resource:
resource_group: "{{ resource_group }}"
provider: ManagedIdentity
resource_type: userAssignedIdentities
resource_name: "{{ item }}"
api_version: "2023-01-31"
body:
location: "{{ location }}"
state: present
loop:
- "ansible-test-iothub-identity"
- "ansible-test-iothub-identity-2"

- name: Set identities IDs to test. Identities ansible-test-iothub-identity and ansible-test-iothub-identity-2 have to be created previously
ansible.builtin.set_fact:
user_identity_1: "/subscriptions/{{ azure_subscription_id }}/resourcegroups/{{ resource_group }}/providers/Microsoft.ManagedIdentity/userAssignedIdentities/ansible-test-iothub-identity"
user_identity_2: "/subscriptions/{{ azure_subscription_id }}/resourcegroups/{{ resource_group }}/providers/Microsoft.ManagedIdentity/userAssignedIdentities/ansible-test-iothub-identity-2"

- name: Create IoT Hub (check mode)
azure_rm_iothub:
Expand Down Expand Up @@ -40,6 +65,36 @@
that:
- iothub.changed

- name: Update IoT Hub (identity)
azure_rm_iothub:
name: "hub{{ rpfx }}"
resource_group: "{{ resource_group }}"
identity:
type: UserAssigned
user_assigned_identities:
id:
- "{{ user_identity_1 }}"
- "{{ user_identity_2 }}"
register: iothub

- name: Assert tht iot hub created
ansible.builtin.assert:
that:
- iothub.changed

- name: Get the IoT Hub facts
azure_rm_iothub_info:
name: "hub{{ rpfx }}"
resource_group: "{{ resource_group }}"
register: iothub

- name: Assert the IoT Hub facts
ansible.builtin.assert:
that:
- iothub.iothubs[0].identity.type == 'UserAssigned'
- user_identity_1 in iothub.iothubs[0].identity.user_assigned_identities
- user_identity_2 in iothub.iothubs[0].identity.user_assigned_identities

- name: Create IoT Hub (idempontent)
azure_rm_iothub:
name: "hub{{ rpfx }}"
Expand All @@ -48,6 +103,12 @@
- name: filter1
action: reject
ip_mask: 40.60.80.10
identity:
type: UserAssigned
user_assigned_identities:
id:
- "{{ user_identity_1 }}"
- "{{ user_identity_2 }}"
register: iothub

- name: Assert the iot hub created
Expand Down Expand Up @@ -180,3 +241,15 @@
ansible.builtin.assert:
that:
- iothub.changed

- name: Destroy User Managed Identities
azure_rm_resource:
resource_group: "{{ resource_group }}"
provider: ManagedIdentity
resource_type: userAssignedIdentities
resource_name: "{{ item }}"
api_version: "2023-01-31"
state: absent
loop:
- "ansible-test-iothub-identity"
- "ansible-test-iothub-identity-2"

0 comments on commit 8d25ffe

Please sign in to comment.