diff --git a/.github/BOTMETA.yml b/.github/BOTMETA.yml index b999b15fa7..9e88561afe 100644 --- a/.github/BOTMETA.yml +++ b/.github/BOTMETA.yml @@ -1029,6 +1029,9 @@ files: - remote_management test/legacy/: notified: mattclay + test/legacy/scaleway: + <<: *scaleway + support: community test/units/modules/network: maintainers: $team_networking labels: networking diff --git a/lib/ansible/modules/cloud/scaleway/scaleway_security_group.py b/lib/ansible/modules/cloud/scaleway/scaleway_security_group.py new file mode 100644 index 0000000000..d6b1009beb --- /dev/null +++ b/lib/ansible/modules/cloud/scaleway/scaleway_security_group.py @@ -0,0 +1,238 @@ +#!/usr/bin/python +# +# Scaleway Security Group management module +# +# Copyright (C) 2018 Antoine Barbare (antoinebarbare@gmail.com). +# +# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) + +from __future__ import absolute_import, division, print_function + +__metaclass__ = type + +ANSIBLE_METADATA = { + 'metadata_version': '1.1', + 'status': ['preview'], + 'supported_by': 'community' +} + +DOCUMENTATION = ''' +--- +module: scaleway_security_group +short_description: Scaleway Security Group management module +version_added: "2.8" +author: Antoine Barbare (@abarbare) +description: + - This module manages Security Group on Scaleway account + U(https://developer.scaleway.com) +extends_documentation_fragment: scaleway + +options: + state: + description: + - Indicate desired state of the Security Group. + default: present + choices: + - present + - absent + + organization: + description: + - Organization identifier + required: true + + region: + description: + - Scaleway region to use (for example C(par1)). + required: true + choices: + - ams1 + - EMEA-NL-EVS + - par1 + - EMEA-FR-PAR1 + + name: + description: + - Name of the Security Group + required: true + + description: + description: + - Description of the Security Group + + stateful: + description: + - Create a stateful security group which allows established connections in and out + required: true + type: bool + + inbound_default_policy: + description: + - Default policy for incoming trafic + choices: + - accept + - drop + + outbound_default_policy: + description: + - Default policy for outcoming trafic + choices: + - accept + - drop + + organization_default: + type: bool + description: + - Create security group to be the default one +''' + +EXAMPLES = ''' + - name: Create a Security Group + scaleway_security_group: + state: present + region: par1 + name: security_group + description: "my security group description" + organization: "43a3b6c8-916f-477b-b7ec-ff1898f5fdd9" + stateful: false + inbound_default_policy: accept + outbound_default_policy: accept + organization_default: false + register: security_group_creation_task +''' + +RETURN = ''' +data: + description: This is only present when C(state=present) + returned: when C(state=present) + type: dict + sample: { + "scaleway_security_group": { + "description": "my security group description", + "enable_default_security": true, + "id": "0168fb1f-cc46-4f69-b4be-c95d2a19bcae", + "inbound_default_policy": "accept", + "name": "security_group", + "organization": "43a3b6c8-916f-477b-b7ec-ff1898f5fdd9", + "organization_default": false, + "outbound_default_policy": "accept", + "servers": [], + "stateful": false + } + } +''' + +from ansible.module_utils.scaleway import SCALEWAY_LOCATION, scaleway_argument_spec, Scaleway +from ansible.module_utils.basic import AnsibleModule +from uuid import uuid4 + + +def payload_from_security_group(security_group): + return dict( + (k, v) + for k, v in security_group.items() + if k != 'id' and v is not None + ) + + +def present_strategy(api, security_group): + ret = {'changed': False} + + response = api.get('security_groups') + if not response.ok: + api.module.fail_json(msg='Error getting security groups "%s": "%s" (%s)' % (response.info['msg'], response.json['message'], response.json)) + + security_group_lookup = dict((sg['name'], sg) + for sg in response.json['security_groups']) + + if security_group['name'] not in security_group_lookup.keys(): + ret['changed'] = True + if api.module.check_mode: + # Help user when check mode is enabled by defining id key + ret['scaleway_security_group'] = {'id': str(uuid4())} + return ret + + # Create Security Group + response = api.post('/security_groups', + data=payload_from_security_group(security_group)) + + if not response.ok: + msg = 'Error during security group creation: "%s": "%s" (%s)' % (response.info['msg'], response.json['message'], response.json) + api.module.fail_json(msg=msg) + ret['scaleway_security_group'] = response.json['security_group'] + + else: + ret['scaleway_security_group'] = security_group_lookup[security_group['name']] + + return ret + + +def absent_strategy(api, security_group): + response = api.get('security_groups') + ret = {'changed': False} + + if not response.ok: + api.module.fail_json(msg='Error getting security groups "%s": "%s" (%s)' % (response.info['msg'], response.json['message'], response.json)) + + security_group_lookup = dict((sg['name'], sg) + for sg in response.json['security_groups']) + if security_group['name'] not in security_group_lookup.keys(): + return ret + + ret['changed'] = True + if api.module.check_mode: + return ret + + response = api.delete('/security_groups/' + security_group_lookup[security_group['name']]['id']) + if not response.ok: + api.module.fail_json(msg='Error deleting security group "%s": "%s" (%s)' % (response.info['msg'], response.json['message'], response.json)) + + return ret + + +def core(module): + security_group = { + 'organization': module.params['organization'], + 'name': module.params['name'], + 'description': module.params['description'], + 'stateful': module.params['stateful'], + 'inbound_default_policy': module.params['inbound_default_policy'], + 'outbound_default_policy': module.params['outbound_default_policy'], + 'organization_default': module.params['organization_default'], + } + + region = module.params['region'] + module.params['api_url'] = SCALEWAY_LOCATION[region]['api_endpoint'] + + api = Scaleway(module=module) + if module.params['state'] == 'present': + summary = present_strategy(api=api, security_group=security_group) + else: + summary = absent_strategy(api=api, security_group=security_group) + module.exit_json(**summary) + + +def main(): + argument_spec = scaleway_argument_spec() + argument_spec.update(dict( + state=dict(default='present', choices=['absent', 'present']), + organization=dict(required=True), + name=dict(required=True), + description=dict(), + region=dict(required=True, choices=SCALEWAY_LOCATION.keys()), + stateful=dict(required=True, type=bool), + inbound_default_policy=dict(choices=['accept', 'drop']), + outbound_default_policy=dict(choices=['accept', 'drop']), + organization_default=dict(type=bool), + )) + module = AnsibleModule( + argument_spec=argument_spec, + supports_check_mode=True, + required_if=[['stateful', True, ['inbound_default_policy', 'outbound_default_policy']]] + ) + + core(module) + + +if __name__ == '__main__': + main() diff --git a/test/legacy/roles/scaleway_security_group/defaults/main.yml b/test/legacy/roles/scaleway_security_group/defaults/main.yml new file mode 100644 index 0000000000..13bbef06af --- /dev/null +++ b/test/legacy/roles/scaleway_security_group/defaults/main.yml @@ -0,0 +1,3 @@ +--- +scaleway_organization: '{{ scw_org }}' +scaleway_region: ams1 diff --git a/test/legacy/roles/scaleway_security_group/tasks/main.yml b/test/legacy/roles/scaleway_security_group/tasks/main.yml new file mode 100644 index 0000000000..068bfe8354 --- /dev/null +++ b/test/legacy/roles/scaleway_security_group/tasks/main.yml @@ -0,0 +1,129 @@ +- name: Create security group check + check_mode: yes + scaleway_security_group: + state: present + region: '{{ scaleway_region }}' + name: security_group + description: 'my security group description' + organization: '{{ scaleway_organization }}' + stateful: false + inbound_default_policy: accept + outbound_default_policy: accept + organization_default: false + register: security_group_creation + +- debug: var=security_group_creation + +- name: Ensure security groups check facts is success + assert: + that: + - security_group_creation is success + - security_group_creation is changed + +- block: + - name: Create security group + scaleway_security_group: + state: present + region: '{{ scaleway_region }}' + name: security_group + description: 'my security group description' + organization: '{{ scaleway_organization }}' + stateful: false + inbound_default_policy: accept + outbound_default_policy: accept + organization_default: false + register: security_group_creation + + - debug: var=security_group_creation + + - name: Ensure security groups facts is success + assert: + that: + - security_group_creation is success + - security_group_creation is changed + + - name: Create security group duplicate + scaleway_security_group: + state: present + region: '{{ scaleway_region }}' + name: security_group + description: 'my security group description' + organization: '{{ scaleway_organization }}' + stateful: false + inbound_default_policy: accept + outbound_default_policy: accept + organization_default: false + register: security_group_creation + + - debug: var=security_group_creation + + - name: Ensure security groups duplicate facts is success + assert: + that: + - security_group_creation is success + - security_group_creation is not changed + + - name: Delete security group check + check_mode: yes + scaleway_security_group: + state: absent + region: '{{ scaleway_region }}' + name: security_group + description: 'my security group description' + organization: '{{ scaleway_organization }}' + stateful: false + inbound_default_policy: accept + outbound_default_policy: accept + organization_default: false + register: security_group_deletion + + - debug: var=security_group_deletion + + - name: Ensure security groups delete check facts is success + assert: + that: + - security_group_deletion is success + - security_group_deletion is changed + + always: + - name: Delete security group + scaleway_security_group: + state: absent + region: '{{ scaleway_region }}' + name: security_group + description: 'my security group description' + organization: '{{ scaleway_organization }}' + stateful: false + inbound_default_policy: accept + outbound_default_policy: accept + organization_default: false + register: security_group_deletion + + - debug: var=security_group_deletion + + - name: Ensure security groups delete facts is success + assert: + that: + - security_group_deletion is success + - security_group_deletion is changed + +- name: Delete security group duplicate + scaleway_security_group: + state: absent + region: '{{ scaleway_region }}' + name: security_group + description: 'my security group description' + organization: '{{ scaleway_organization }}' + stateful: false + inbound_default_policy: accept + outbound_default_policy: accept + organization_default: false + register: security_group_deletion + +- debug: var=security_group_deletion + +- name: Ensure security groups delete duplicate facts is success + assert: + that: + - security_group_deletion is success + - security_group_deletion is not changed \ No newline at end of file diff --git a/test/legacy/scaleway.yml b/test/legacy/scaleway.yml index b242d99c29..5e173023ed 100644 --- a/test/legacy/scaleway.yml +++ b/test/legacy/scaleway.yml @@ -18,3 +18,4 @@ - { role: scaleway_user_data, tags: test_scaleway_user_data } - { role: scaleway_volume, tags: test_scaleway_volume } - { role: scaleway_volume_facts, tags: test_scaleway_volume_facts } + - { role: scaleway_security_group, tags: test_scaleway_security_group }