Skip to content

Commit 504e7ca

Browse files
authored
Merge pull request #4 from merizrizal/3-implement-idempotency-in-the-vm-and-network-modules
3 implement idempotency in the vm and network modules
2 parents b8db776 + fcf83e7 commit 504e7ca

File tree

8 files changed

+713
-18
lines changed

8 files changed

+713
-18
lines changed

README.md

Lines changed: 59 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,63 @@ target:
2222

2323
Then write the playbook.yml file.
2424

25+
Example of using the Network module.
26+
```
27+
---
28+
- name: ID Cloud Host Setup
29+
hosts: idch
30+
tasks:
31+
- name: Create network VPC resource
32+
merizrizal.idcloudhost.network:
33+
api_key: "{{ your_api_key }}"
34+
name: "{{ your_desired_network_name }}"
35+
location: jkt02
36+
# Since the default value of state is set to present, we may exclude it
37+
state: present
38+
39+
- name: Delete network VPC resource
40+
merizrizal.idcloudhost.network:
41+
api_key: "{{ your_api_key }}"
42+
name: "{{ your_desired_network_name }}"
43+
location: jkt02
44+
state: absent
45+
```
46+
To see the module documentation, run `ansible-doc merizrizal.idcloudhost.network`
47+
48+
Example of using the VM module.
49+
```
50+
---
51+
- name: ID Cloud Host Setup
52+
hosts: idch
53+
tasks:
54+
- name: Create VM resource
55+
merizrizal.idcloudhost.vm:
56+
api_key: "{{ your_api_key }}"
57+
location: jkt02
58+
network_name: "{{ your_desired_network_name }}"
59+
name: "{{ your_desired_vm_name }}"
60+
os_name: ubuntu
61+
os_version: 24.04-lts
62+
disks: 20
63+
vcpu: 2
64+
ram: 2048
65+
username: admin
66+
password: My4adminpass
67+
# Since the default value of state is set to present, we may exclude it
68+
state: present
69+
70+
- name: Delete VM resource
71+
merizrizal.idcloudhost.vm:
72+
api_key: "{{ your_api_key }}"
73+
location: jkt02
74+
name: "{{ your_desired_vm_name }}"
75+
remove_public_ipv4: false
76+
state: absent
77+
```
78+
To see the module documentation, run `ansible-doc merizrizal.idcloudhost.vm`
79+
80+
### _The initial modules below will be removed later_
81+
2582
Example for creating network resource.
2683
```
2784
---
@@ -34,7 +91,7 @@ Example for creating network resource.
3491
name: "{{ your_desired_network_name }}"
3592
location: jkt02
3693
```
37-
To see the module documention, run `ansible-doc merizrizal.idcloudhost.create_network`
94+
To see the module documentation, run `ansible-doc merizrizal.idcloudhost.create_network`
3895

3996
Example for creating a new VM and get its publid IP address.
4097
```
@@ -75,7 +132,7 @@ Example for creating a new VM and get its publid IP address.
75132
location: jkt02
76133
vm_uuid: "{{ create_vm_result.uuid }}
77134
```
78-
To see the module documention, run:
135+
To see the module documentation, run:
79136
- `ansible-doc merizrizal.idcloudhost.get_network`
80137
- `ansible-doc merizrizal.idcloudhost.create_vm`
81138
- `ansible-doc merizrizal.idcloudhost.get_public_ip`
Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
# -*- coding: utf-8 -*-
2+
# Copyright (c) 2025, Mei Rizal (@merizrizal) <meriz.rizal@gmail.com>
3+
# Simplified BSD License (see licenses/simplified_bsd.txt or https://opensource.org/licenses/BSD-2-Clause)
4+
from ansible.module_utils.basic import AnsibleModule
5+
6+
requests = None
7+
8+
9+
class Base(object):
10+
def __init__(self):
11+
self._base_url = 'https://api.idcloudhost.com/v1'
12+
self._endpoint_url = ''
13+
self._api_key = ''
14+
self._name = ''
15+
self._location = ''
16+
self._state = 'present'
17+
18+
self._module: AnsibleModule = None
19+
20+
def _ensure_requests(self):
21+
try:
22+
import requests
23+
HAS_REQUESTS = True
24+
except ImportError:
25+
HAS_REQUESTS = False
26+
27+
if HAS_REQUESTS:
28+
return requests
29+
30+
if self._module:
31+
self._module.fail_json(
32+
msg='Could not import the requests Python module',
33+
results=[]
34+
)
35+
36+
def _get_existing_network(self, name) -> dict:
37+
url = f'{self._base_url}/{self._location}/network/networks'
38+
url_headers = dict(
39+
apikey=self._api_key
40+
)
41+
42+
global requests
43+
requests = self._ensure_requests()
44+
response = requests.request('GET', url, headers=url_headers, timeout=360)
45+
data = response.json()
46+
47+
if isinstance(data, list) and len(data) > 0:
48+
for value in data:
49+
if value['name'] == name:
50+
network = dict(
51+
uuid=value['uuid'],
52+
name=value['name'],
53+
subnet=value['subnet'],
54+
is_default=value['is_default']
55+
)
56+
57+
return network
58+
59+
return dict()
60+
61+
def _get_public_ipv4(self, vm_uuid=None, private_ipv4=None) -> dict:
62+
url = f'{self._base_url}/{self._location}/network/ip_addresses'
63+
url_headers = dict(
64+
apikey=self._api_key
65+
)
66+
67+
global requests
68+
requests = self._ensure_requests()
69+
response = requests.request('GET', url, headers=url_headers, timeout=360)
70+
data = response.json()
71+
72+
if isinstance(data, list) and len(data) > 0:
73+
for value in data:
74+
is_found = value['assigned_to_private_ip'] == private_ipv4
75+
is_found = is_found or value['assigned_to'] == vm_uuid
76+
77+
if is_found:
78+
result = dict(
79+
uuid=value['uuid'],
80+
public_ipv4=value['address'],
81+
enabled=value['enabled']
82+
)
83+
84+
return result
85+
86+
return dict()

merizrizal/idcloudhost/plugins/modules/create_network.py

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -22,15 +22,15 @@
2222
description: API of idcloudhost.com uses tokens to allow access to the API.
2323
required: true
2424
type: str
25-
name:
26-
description: Name of network that will be created.
27-
required: true
28-
type: str
2925
location:
3026
description: The location name of the network to which this network will be assigned.
3127
required: true
3228
type: str
3329
choices: [ jkt01, jkt02, jkt03, sgp01 ]
30+
name:
31+
description: Name of network that will be created.
32+
required: true
33+
type: str
3434
3535
author:
3636
- Mei Rizal (@merizrizal) <meriz.rizal@gmail.com>
@@ -40,8 +40,8 @@
4040
- name: Create new VPC network
4141
merizrizal.idcloudhost.create_network:
4242
api_key: 2bnQkD6yOb7OkSwVCBXJSg1AHpfd99oY
43-
name: my_vpc_network_01
4443
location: jkt01
44+
name: my_vpc_network_01
4545
'''
4646

4747
RETURN = r'''
@@ -109,7 +109,7 @@ def main(self):
109109
error=data
110110
)
111111

112-
module.fail_json(msg='Create network fail', **result)
112+
module.fail_json(msg='Failed to create the VPC network.', **result)
113113
else:
114114
result = dict(
115115
uuid=data['uuid'],

merizrizal/idcloudhost/plugins/modules/create_vm.py

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -91,7 +91,7 @@
9191

9292
EXAMPLES = r'''
9393
- name: Create new VM
94-
merizrizal.idcloudhost.create_network:
94+
merizrizal.idcloudhost.create_vm:
9595
api_key: 2bnQkD6yOb7OkSwVCBXJSg1AHpfd99oY
9696
location: jkt01
9797
network_uuid: "{{ get_from_get_network.uuid }}"
@@ -115,7 +115,7 @@
115115
type: str
116116
returned: success
117117
private_ipv4:
118-
description: Private IPv4 of the created VM.
118+
description: Private IPv4 address of the created VM.
119119
type: str
120120
returned: success
121121
billing_account:
@@ -131,7 +131,7 @@
131131
requests = None
132132

133133

134-
class CreateVM():
134+
class CreateVm():
135135
def __init__(self):
136136
self.base_url = 'https://api.idcloudhost.com/v1'
137137
self.endpoint_url = 'user-resource/vm'
@@ -194,7 +194,7 @@ def main(self):
194194
error=f'Selected os_name is {os_name} then os_version must be one of {os_version_choices[os_name]}, got {os_version}'
195195
)
196196

197-
module.fail_json(msg='Create VM fail', **result)
197+
module.fail_json(msg='Failed to create the VM.', **result)
198198

199199
url = f'{self.base_url}/{self.location}/{self.endpoint_url}'
200200
url_headers = {
@@ -222,7 +222,7 @@ def main(self):
222222
error=data
223223
)
224224

225-
module.fail_json(msg='Create VM fail', **data)
225+
module.fail_json(msg='Failed to create the VM.', **data)
226226
else:
227227
result = dict(
228228
uuid=data['uuid'],
@@ -235,4 +235,4 @@ def main(self):
235235

236236

237237
if __name__ == '__main__':
238-
CreateVM().main()
238+
CreateVm().main()

merizrizal/idcloudhost/plugins/modules/get_network.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -97,7 +97,7 @@ def main(self):
9797
error=data
9898
)
9999

100-
module.fail_json(msg='Get network fail', **result)
100+
module.fail_json(msg='Failed to get the VPC network.', **result)
101101
else:
102102
for value in data:
103103
if value['is_default']:

merizrizal/idcloudhost/plugins/modules/get_public_ip.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,7 @@
7272
type: bool
7373
returned: success, when private_ipv4 is selected
7474
assigned_to_private_ip:
75-
description: On which private Ipv4 this public IPv4 is assigned.
75+
description: On which private IPv4 address this public IPv4 address is assigned.
7676
type: bool
7777
returned: success, when vm_uuid is selected
7878
'''
@@ -132,7 +132,7 @@ def main(self):
132132
error=data
133133
)
134134

135-
module.fail_json(msg='Get public IPv4 fail', **result)
135+
module.fail_json(msg='Failed to get the public IPv4 address.', **result)
136136
else:
137137
result = dict(
138138
error='Public IPv4 address is not found'
@@ -156,7 +156,7 @@ def main(self):
156156

157157
module.exit_json(**result)
158158

159-
module.fail_json(msg='Get public IPv4 fail', **result)
159+
module.fail_json(msg='Failed to get the public IPv4 address', **result)
160160

161161

162162
if __name__ == '__main__':

0 commit comments

Comments
 (0)