Skip to content
This repository was archived by the owner on Jul 17, 2023. It is now read-only.

Commit dcb398f

Browse files
Include ability to resize, attach, and detach volumes (#14)
1 parent 17f1d2c commit dcb398f

File tree

7 files changed

+364
-11
lines changed

7 files changed

+364
-11
lines changed
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
minor_changes:
2+
- vultr_block_storage - Included ability to resize, attach and detach Block Storage Volumes.

galaxy.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,4 +16,4 @@ tags:
1616
- cloud
1717
- vultr
1818
- ngine_io
19-
version: 1.0.0
19+
version: 1.1.0

plugins/modules/vultr_block_storage.py

Lines changed: 141 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
description:
2828
- Size of the block storage volume in GB.
2929
- Required if I(state) is present.
30+
- If it's larger than the volume's current size, the volume will be resized.
3031
type: int
3132
region:
3233
description:
@@ -37,8 +38,19 @@
3738
description:
3839
- State of the block storage volume.
3940
default: present
40-
choices: [ present, absent ]
41+
choices: [ present, absent, attached, detached ]
4142
type: str
43+
attached_to_SUBID:
44+
description:
45+
- The ID of the server the volume is attached to.
46+
- Required if I(state) is attached.
47+
aliases: [ attached_to_id ]
48+
type: int
49+
live_attachment:
50+
description:
51+
- Whether the volume should be attached/detached, even if the server not stopped.
52+
type: bool
53+
default: True
4254
extends_documentation_fragment:
4355
- ngine_io.vultr.vultr
4456
@@ -55,6 +67,19 @@
5567
ngine_io.vultr.vultr_block_storage:
5668
name: myvolume
5769
state: absent
70+
71+
- name: Ensure a block storage volume exists and is attached to server 114
72+
ngine_io.vultr.vultr_block_storage:
73+
name: myvolume
74+
state: attached
75+
attached_to_id: 114
76+
size: 10
77+
78+
- name: Ensure a block storage volume exists and is not attached to any server
79+
ngine_io.vultr.vultr_block_storage:
80+
name: myvolume
81+
state: detached
82+
size: 10
5883
'''
5984

6085
RETURN = '''
@@ -136,7 +161,6 @@
136161
sample: "active"
137162
138163
'''
139-
140164
from ansible.module_utils.basic import AnsibleModule
141165
from ..module_utils.vultr import (
142166
Vultr,
@@ -216,28 +240,140 @@ def absent_block_storage_volume(self):
216240
)
217241
return volume
218242

243+
def detached_block_storage_volume(self):
244+
volume = self.present_block_storage_volume()
245+
if volume.get('attached_to_SUBID') is None:
246+
return volume
247+
248+
self.result['changed'] = True
249+
250+
if not self.module.check_mode:
251+
data = {
252+
'SUBID': volume['SUBID'],
253+
'live': self.get_yes_or_no('live_attachment')
254+
}
255+
self.api_query(
256+
path='/v1/block/detach',
257+
method='POST',
258+
data=data
259+
)
260+
261+
volume = self.get_block_storage_volumes()
262+
else:
263+
volume['attached_to_SUBID'] = None
264+
265+
self.result['diff']['after'] = volume
266+
267+
return volume
268+
269+
def attached_block_storage_volume(self):
270+
expected_server = self.module.params.get('attached_to_SUBID')
271+
volume = self.present_block_storage_volume()
272+
server = volume.get('attached_to_SUBID')
273+
if server == expected_server:
274+
return volume
275+
276+
if server is not None:
277+
self.module.fail_json(
278+
msg='Volume already attached to server %s' % server
279+
)
280+
281+
self.result['changed'] = True
282+
283+
if not self.module.check_mode:
284+
data = {
285+
'SUBID': volume['SUBID'],
286+
# This API call expects a param called attach_to_SUBID,
287+
# but all the BlockStorage API response payloads call
288+
# this parameter attached_to_SUBID. So we'll standardize
289+
# to the latter and attached_to_id, but we'll pass the
290+
# expected attach_to_SUBID to this API call.
291+
'attach_to_SUBID': expected_server,
292+
'live': self.get_yes_or_no('live_attachment'),
293+
}
294+
self.api_query(
295+
path='/v1/block/attach',
296+
method='POST',
297+
data=data
298+
)
299+
volume = self.get_block_storage_volumes()
300+
else:
301+
volume['attached_to_SUBID'] = expected_server
302+
303+
self.result['diff']['after'] = volume
304+
305+
return volume
306+
307+
def ensure_volume_size(self, volume, expected_size):
308+
curr_size = volume.get('size_gb')
309+
# When creating, attaching, or detaching a volume in check_mode,
310+
# sadly, size_gb doesn't exist, because those methods return the
311+
# result of get_block_storage_volumes, which is {} on check_mode.
312+
if curr_size is None or curr_size >= expected_size:
313+
# we only resize volumes that are smaller than
314+
# expected. There's no shrinking operation.
315+
return volume
316+
317+
self.result['changed'] = True
318+
319+
volume['size_gb'] = expected_size
320+
self.result['diff']['after'] = volume
321+
322+
if not self.module.check_mode:
323+
data = {'SUBID': volume['SUBID'], 'size_gb': expected_size}
324+
self.api_query(
325+
path='/v1/block/resize',
326+
method='POST',
327+
data=data,
328+
)
329+
330+
return volume
331+
219332

220333
def main():
221334
argument_spec = vultr_argument_spec()
222335
argument_spec.update(dict(
223336
name=dict(type='str', required=True, aliases=['description', 'label']),
224337
size=dict(type='int'),
225338
region=dict(type='str'),
226-
state=dict(type='str', choices=['present', 'absent'], default='present'),
339+
state=dict(
340+
type='str',
341+
choices=['present', 'absent', 'attached', 'detached'],
342+
default='present'
343+
),
344+
attached_to_SUBID=dict(type='int', aliases=['attached_to_id']),
345+
live_attachment=dict(type='bool', default=True)
227346
))
228347

229348
module = AnsibleModule(
230349
argument_spec=argument_spec,
231350
supports_check_mode=True,
232-
required_if=[['state', 'present', ['size', 'region']]]
351+
required_if=[
352+
['state', 'present', ['size', 'region']],
353+
['state', 'detached', ['size', 'region']],
354+
['state', 'attached', ['size', 'region', 'attached_to_SUBID']],
355+
]
233356
)
234357

235358
vultr_block_storage = AnsibleVultrBlockStorage(module)
236-
if module.params.get('state') == "absent":
359+
360+
desired_state = module.params.get('state')
361+
if desired_state == "absent":
237362
volume = vultr_block_storage.absent_block_storage_volume()
363+
elif desired_state == 'attached':
364+
volume = vultr_block_storage.attached_block_storage_volume()
365+
elif desired_state == 'detached':
366+
volume = vultr_block_storage.detached_block_storage_volume()
238367
else:
239368
volume = vultr_block_storage.present_block_storage_volume()
240369

370+
expected_size = module.params.get('size')
371+
if expected_size and desired_state != 'absent':
372+
volume = vultr_block_storage.ensure_volume_size(
373+
volume,
374+
expected_size
375+
)
376+
241377
result = vultr_block_storage.get_result(volume)
242378
module.exit_json(**result)
243379

plugins/modules/vultr_server.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,7 @@
5656
- Whether to send an activation email when the server is ready or not.
5757
- Only considered on creation.
5858
type: bool
59+
default: false
5960
private_network_enabled:
6061
description:
6162
- Whether to enable private networking or not.

plugins/modules/vultr_server_baremetal.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@
4444
- Whether to send an activation email when the server is ready or not.
4545
- Only considered on creation.
4646
type: bool
47+
default: false
4748
ipv6_enabled:
4849
description:
4950
- Whether to enable IPv6 or not.

tests/integration/targets/vultr_block_storage/defaults/main.yml

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,4 +2,13 @@
22
vultr_resource_prefix: "vultr-test-prefix"
33
vultr_block_storage_name: "{{ vultr_resource_prefix }}-volume"
44
vultr_block_storage_size: 10
5+
vultr_block_storage_size_2: 12
6+
vultr_block_storage_size_3: 14
57
vultr_block_storage_region: New Jersey
8+
9+
vultr_server_name: "{{ vultr_resource_prefix }}_vm_for_attachment"
10+
vultr_server_ssh_keys:
11+
- name: key1
12+
key: "ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAgEAyWYItY+3w5b8PdGRoz0oY5mufqydW96naE+VM3JSvJFAUS08rAjQQpQ03ymoALeHQy6JVZbcgecxn6p0pAOINQdqufn4udPtOPCtMjNiPGpkSM9ah/6X5+kvyWMNrvlf+Ld4OOoszP5sAkgQzIbrFQAm41XknBUha0zkewZwfrVhain4pnDjV7wCcChId/Q/Gbi4xMtXkisznWcAJcueBs3EEZDKhJ5q0VeWSJEhYJDLFN1sOxF0AIUnMrOhfKQ/LjgREXPB6uCl899INUTXRNNjRpeMXyJ2wMMmOAbua2qEd1r13Bu1n+6A823Hzb33fyMXuqWnJwBJ4DCvMlGuEsfuOK+xk7DaBfLHbcM6fsPk0/4psTE6YLgC41remr6+u5ZWsY/faMtSnNPie8Z8Ov0DIYGdhbJjUXk1HomxRV9+ZfZ2Ob8iCwlaAQAyEUM6fs3Kxt8pBD8dx1HOkhsfBWPvuDr5y+kqE7H8/MuPDTc0QgH2pjUMpmw/XBwNDHshVEjrZvtICOjOLUJxcowLO1ivNYwPwowQxfisMy56LfYdjsOslBiqsrkAqvNGm1zu8wKHeqVN9w5l3yUELpvubfm9NKIvYcl6yWF36T0c5vE+g0DU/Jy4XpTj0hZG9QV2mRQcLJnd2pxQtJT7cPFtrn/+tgRxzjEtbDXummDV4sE= mail@renemoser.net"
13+
14+
vultr_server_plan_1: 1024 MB RAM,25 GB SSD,1.00 TB BW

0 commit comments

Comments
 (0)