diff --git a/README.md b/README.md index 08af3d7..0aa1cc6 100644 --- a/README.md +++ b/README.md @@ -5,7 +5,7 @@ An Ansible Role that sets up automated remote backups on the target machine. Use ## Role Variables ### Required Arguments -- `borg_repository`: Full path to repository. Your own server or [BorgBase.com](https://www.borgbase.com) repo. +- `borg_repository`: Full path to repository. Your own server or [BorgBase.com](https://www.borgbase.com) repo. Only required if not using the [BorgBase.com](https://www.borgbase.com) auto creation of repositories. - `borg_source_directories`: List of local folders to back up. ### Optional Arguments @@ -20,6 +20,18 @@ An Ansible Role that sets up automated remote backups on the target machine. Use - `borg_encryption_passcommand`: The standard output of this command is used to unlock the encryption key. - `borg_retention_policy`: Retention policy for how many backups to keep in each category (daily, weekly, monthly, etc). +### Optional Arguments for [BorgBase.com](https://www.borgbase.com) repository auto creation +- `create_repo`: Whether to let the role create the repository for the server. Default: False +- `bb_token`: Your [BorgBase.com](https://www.borgbase.com) API-Token. Should be Create Only for security reasons. +- `bb_region`: Which region the backups should be saved in. Choice: "eu" or "us". +- `bb_new_sshkey`: Whether to use the automatically created SSH_key. Default: True +- `bb_sshkey`: If there is a key already available on [BorgBase.com](https://www.borgbase.com) that should be used, it can be set with this variable. The key needs to be exactly the same, including key-comment. +- `bb_append`: Should the permission of the newly created repository be append only? Default: True +- `bb_quota`: To use a quota for the Server. Default: False +- `bb_quota_size`: Will need to be set if `bb_quota` is set to True. In Gigabyte. +- `bb_alertdays`: After how many days of no backup activity should alerts be sent out? Defaults to off. +- `bb_repo_name`: What name the created repository should have. Defaults to the inventory_hostname. + ## Example Playbook ``` diff --git a/defaults/main.yml b/defaults/main.yml index 7d01d05..0cbdaa3 100755 --- a/defaults/main.yml +++ b/defaults/main.yml @@ -13,3 +13,11 @@ borg_retention_policy: keep_daily: 7 keep_weekly: 4 keep_monthly: 6 +create_repo: False +bb_new_sshkey: True +bb_append: True +bb_quota: False +bb_quota_size: 0 +bb_alertdays: 0 +bb_repo_name: "{{ inventory_hostname }}" +bb_sshkey: "{{ root_user['ssh_public_key'] }}" diff --git a/library/borgbase.py b/library/borgbase.py new file mode 100644 index 0000000..74b8b9b --- /dev/null +++ b/library/borgbase.py @@ -0,0 +1,168 @@ +#!/usr/bin/python + +DOCUMENTATION = ''' +--- +module: borgbase +author: "Philipp Rintz (https://github.com/p-rintz)" +short_description: Ansible module for creating new repositories with borgbase.com +description: + - Ansible Module for creating new repositories with borgbase.com including adding new ssh keys +version_added: "2.6" +''' + +EXAMPLES = ''' +- name: Create new repository for server in EU with new SSH_key and quota + borgbase: + repository_name: "{{ inventory_hostname }}" + token: "Your Borgbase API Token" + new_ssh_key: True + ssh_key: "{{ some_variable }}" + append_only: True + quota_enable: True + quota: 1000 #in GB + region: eu + alertdays: 2 + delegate_to: localhost +- name: Create new repository without new key and no quota/alerting in US region + borgbase: + repository_name: "{{ inventory_hostname }}" + token: "Your Borgbase API Token" + new_ssh_key: False + ssh_key: "ssh-ed25519 AAAAC3Nz......aLqRJw+dl/E+2BJ xxx@yyy" + region: us + delegate_to: localhost +''' + +from ansible.module_utils.basic import * +from ansible.module_utils.borgbase_api_client.client import GraphQLClient +from ansible.module_utils.borgbase_api_client.mutations import * +from ansible.module_utils.borgbase_api_client.queries import * + + +def get_key_id(ssh_key): + res = client.execute(KEY_DETAILS) + for i in res['data']['sshList']: + if i['keyData'] == ssh_key: + key_id = i['id'] + return key_id + +def add_ssh_key(): + key_name = 'Key for %s' % (module.params['repository_name'],) + new_key_vars = { + 'name': key_name, + 'keyData': module.params['ssh_key'] + } + res = client.execute(SSH_ADD, new_key_vars) + new_key_id = res['data']['sshAdd']['keyAdded']['id'] + return new_key_id + +def add_repo(key_id): + if module.params['append_only']: + access_level = 'appendOnlyKeys' + else: + access_level = 'fullAccessKeys' + + if not module.params['quota_enable']: + new_repo_vars = { + 'name': module.params['repository_name'], + 'quotaEnabled': module.params['quota_enable'], + access_level: [key_id], + 'alertDays': module.params['alertdays'], + 'region': module.params['region'] + } + else: + new_repo_vars = { + 'name': module.params['repository_name'], + 'quotaEnabled': module.params['quota_enable'], + 'quota': 1000*module.params['quota'], + access_level: [key_id], + 'alertDays': module.params['alertdays'], + 'region': module.params['region'] + } + res = client.execute(REPO_ADD, new_repo_vars) + return res + +def main(): + global module + module = AnsibleModule( + argument_spec = dict( + repository_name = dict( + type='str', + required=True, + ), + token = dict( + required=True, + type='str', + no_log=True + ), + new_ssh_key = dict( + required=False, + default='True', + type='bool' + ), + ssh_key = dict( + required=True, + type='str' + ), + append_only = dict( + required=False, + default='True', + type='bool' + ), + quota_enable = dict( + required=False, + default='False', + type='bool' + ), + quota = dict( + required=False, + type='int' + ), + region = dict( + required=True, + type='str', + choice=["eu", "us"] + ), + alertdays = dict( + required=False, + default=0, + type='int' + ) + ) + ) + + global client + client = GraphQLClient(module.params['token']) + + # Add new SSH key or get ID of old key + if module.params['new_ssh_key']: + key_id = add_ssh_key() + else: + key_id = get_key_id(module.params['ssh_key']) + + # Add new repo using the key + res = add_repo(key_id) + + # Setup information for Ansible + result = dict( + changed = False, + data = '', + type = '', + key_id = '' + ) + + # Test for success and change info + if type(res) == dict: + result['changed'] = True + result['data'] = res['data']['repoAdd']['repoAdded'] + result['key_id'] = key_id + module.exit_json(**result) + else: + result['data'] = res + result['type'] = type(res) + result['key_id'] = key_id + module.fail_json(msg="Failed creating new respository.", **result) + + +if __name__ == '__main__': + main() diff --git a/module_utils/README b/module_utils/README new file mode 100644 index 0000000..7249b31 --- /dev/null +++ b/module_utils/README @@ -0,0 +1,6 @@ +The "borgbase_api_client" folder of the API client repository will need to be put into this folder. + +Folder structure: +ansible-role-borgbackup/ +|---------------------+ module_utils/ + |-------- borgbase_api_client/ diff --git a/tasks/main.yml b/tasks/main.yml index d8818f9..d5badb5 100755 --- a/tasks/main.yml +++ b/tasks/main.yml @@ -5,7 +5,7 @@ - name: Install required System Packages package: pkg: "{{ item }}" - state: installed + state: present with_items: "{{ borg_packages }}" - name: Update setuptools if needed @@ -31,6 +31,27 @@ - debug: var: root_user['ssh_public_key'] +- name: Create new repository for server + borgbase: + repository_name: "{{ bb_repo_name }}" + token: "{{ bb_token}}" + new_ssh_key: "{{ bb_new_sshkey }}" + ssh_key: "{{ bb_sshkey }}" + append_only: "{{ bb_append }}" + quota_enable: "{{ bb_quota }}" + quota: "{{ bb_quota_size }}" + region: "{{ bb_region }}" + alertdays: "{{ bb_alertdays }}" + delegate_to: localhost + become: no + register: repo_creation + when: create_repo + +- name: Set Repository Fact + set_fact: + borg_repository: "{{ repo_creation['data']['repoPath'] }}" + when: create_repo + - name: Ensures /etc/borgmatic exists file: path: /etc/borgmatic