From f6cf1411a177a1405b810ae9c65b21995303ca2c Mon Sep 17 00:00:00 2001 From: Monty Taylor Date: Tue, 31 Mar 2015 16:37:07 -0400 Subject: [PATCH 1/3] Add OpenStack Server Volume module --- cloud/openstack/os_server_volume.py | 130 ++++++++++++++++++++++++++++ 1 file changed, 130 insertions(+) create mode 100644 cloud/openstack/os_server_volume.py diff --git a/cloud/openstack/os_server_volume.py b/cloud/openstack/os_server_volume.py new file mode 100644 index 00000000000..2031262c2c7 --- /dev/null +++ b/cloud/openstack/os_server_volume.py @@ -0,0 +1,130 @@ +#!/usr/bin/python +#coding: utf-8 -*- + +# Copyright (c) 2014 Hewlett-Packard Development Company, L.P. +# +# This module is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This software is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this software. If not, see . + + +try: + import shade + from shade import meta + HAS_SHADE = True +except ImportError: + HAS_SHADE = False + + +DOCUMENTATION = ''' +--- +module: os_server_volume +short_description: Attach/Detach Volumes from OpenStack VM's +extends_documentation_fragment: openstack +version_added: "1.10" +description: + - Attach or Detach volumes from OpenStack VM's +options: + state: + description: + - Indicate desired state of the resource + choices: ['present', 'absent'] + default: present + server: + description: + - Name or ID of server you want to attach a volume to + required: true + default: None + volume: + description: + - Name or id of volume you want to attach to a server + required: true + device: + description: + - Device you want to attach. Defaults to auto finding a device name. + required: false + default: None + state: + description: + - Should the resource be present or absent. + choices: [present, absent] + default: present +requirements: ["shade"] +''' + +EXAMPLES = ''' +# Attaches a volume to a compute host +- name: attach a volume + hosts: localhost + tasks: + - name: attach volume to host + os_server_volume: + state: present + cloud: mordred + server: Mysql-server + volume: mysql-data + device: /dev/vdb +''' + + +def main(): + argument_spec = openstack_full_argument_spec( + server=dict(required=True), + volume=dict(required=True), + device=dict(default=None), # None == auto choose device name + state=dict(default='present', choices=['absent', 'present']), + ) + + module_kwargs = openstack_module_kwargs() + module = AnsibleModule(argument_spec, **module_kwargs) + + if not HAS_SHADE: + module.fail_json(msg='shade is required for this module') + + state = module.params['state'] + wait = module.params['wait'] + timeout = module.params['timeout'] + + try: + cloud = shade.openstack_cloud(**module.params) + server = cloud.get_server(module.params['server']) + volume = cloud.get_volume(module.params['volume']) + + if state == 'present': + cloud.attach_volume(server, volume, module.params['device'], + wait=wait, timeout=timeout) + + server = cloud.get_server(module.params['server']) # refresh + volume = cloud.get_volume(module.params['volume']) # refresh + hostvars = meta.get_hostvars_from_server(cloud, server) + + module.exit_json( + changed=True, + id=volume.id, + attachments=volume.attachments, + openstack=hostvars + ) + + elif state == 'absent': + cloud.detach_volume(server, volume, wait=wait, timeout=timeout) + module.exit_json( + changed=True, + result='Detached volume from server' + ) + + except (shade.OpenStackCloudException, shade.OpenStackCloudTimeout) as e: + module.fail_json(msg=e.message) + +# this is magic, see lib/ansible/module_utils/common.py +from ansible.module_utils.basic import * +from ansible.module_utils.openstack import * +main() From 4a233a5a8f6343c03bc3a6cec1d7a4f096468e8f Mon Sep 17 00:00:00 2001 From: David Shrewsbury Date: Tue, 7 Apr 2015 14:37:06 -0400 Subject: [PATCH 2/3] Recognize when volume attach/detach is not necessary Do not attempt to attach an already attached volume. Likewise, do not attempt to detach a volume that is not attached. This version adds support for check mode. --- cloud/openstack/os_server_volume.py | 37 ++++++++++++++++++++++------- 1 file changed, 29 insertions(+), 8 deletions(-) diff --git a/cloud/openstack/os_server_volume.py b/cloud/openstack/os_server_volume.py index 2031262c2c7..35ad3287d6c 100644 --- a/cloud/openstack/os_server_volume.py +++ b/cloud/openstack/os_server_volume.py @@ -36,8 +36,8 @@ description: options: state: description: - - Indicate desired state of the resource - choices: ['present', 'absent'] + - Should the resource be present or absent. + choices: [present, absent] default: present server: description: @@ -53,11 +53,6 @@ options: - Device you want to attach. Defaults to auto finding a device name. required: false default: None - state: - description: - - Should the resource be present or absent. - choices: [present, absent] - default: present requirements: ["shade"] ''' @@ -76,6 +71,18 @@ EXAMPLES = ''' ''' +def _system_state_change(state, device): + """Check if system state would change.""" + if state == 'present': + if device: + return False + return True + if state == 'absent': + if device: + return True + return False + return False + def main(): argument_spec = openstack_full_argument_spec( server=dict(required=True), @@ -85,7 +92,9 @@ def main(): ) module_kwargs = openstack_module_kwargs() - module = AnsibleModule(argument_spec, **module_kwargs) + module = AnsibleModule(argument_spec, + supports_check_mode=True, + **module_kwargs) if not HAS_SHADE: module.fail_json(msg='shade is required for this module') @@ -98,8 +107,16 @@ def main(): cloud = shade.openstack_cloud(**module.params) server = cloud.get_server(module.params['server']) volume = cloud.get_volume(module.params['volume']) + dev = cloud.get_volume_attach_device(volume, server.id) + + if module.check_mode: + module.exit_json(changed=_system_state_change(state, dev)) if state == 'present': + if dev: + # Volume is already attached to this server + module.exit_json(changed=False) + cloud.attach_volume(server, volume, module.params['device'], wait=wait, timeout=timeout) @@ -115,6 +132,10 @@ def main(): ) elif state == 'absent': + if not dev: + # Volume is not attached to this server + module.exit_json(changed=False) + cloud.detach_volume(server, volume, wait=wait, timeout=timeout) module.exit_json( changed=True, From c451fbdd618270f7b39ba13eacfce41df8d53335 Mon Sep 17 00:00:00 2001 From: David Shrewsbury Date: Thu, 23 Apr 2015 10:52:08 -0400 Subject: [PATCH 3/3] Update os_server_volume for latest shade The shade volume API was updated to return a dict rather than the object as returned by cinder. --- cloud/openstack/os_server_volume.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cloud/openstack/os_server_volume.py b/cloud/openstack/os_server_volume.py index 35ad3287d6c..3355ee404d8 100644 --- a/cloud/openstack/os_server_volume.py +++ b/cloud/openstack/os_server_volume.py @@ -126,8 +126,8 @@ def main(): module.exit_json( changed=True, - id=volume.id, - attachments=volume.attachments, + id=volume['id'], + attachments=volume['attachments'], openstack=hostvars )