Skip to content

Commit

Permalink
Made borgbase module idempotent.
Browse files Browse the repository at this point in the history
  • Loading branch information
apollo13 committed Nov 16, 2019
1 parent ca6e674 commit e4d1e76
Show file tree
Hide file tree
Showing 5 changed files with 114 additions and 138 deletions.
2 changes: 1 addition & 1 deletion LICENSE.3rdparty
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
The `borgbase` ansible module is taken from https://github.com/borgbase/ansible-role-borgbackup which is also MIT licensed.
The `borgbase` ansible module is highly adapted from https://github.com/borgbase/ansible-role-borgbackup which is also MIT licensed.
The current license text can be found at: https://github.com/borgbase/ansible-role-borgbackup/blob/c1fd4e5c80349fb338748daf08cf41cf6a2b6bb4/LICENSE

The `borgbase_api_client` is taken from https://github.com/borgbase/borgbase-api-client which is also MIT licensed.
Expand Down
4 changes: 1 addition & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -68,9 +68,7 @@ To enable support for borgbase.com the following variables need to be defined:
borgbackup_bb_repo: borgbase repository name
borgbackup_bb_apikey: borgbase api key
```
Once those are set `borgbackup_repository` will be defined automatically. Creation of the repository depends on the existance of a file
named `{{ borgbackup_home }}/data/borgbase_repo_info` which contains the repository URL. This file must stay there, otherwise the repo
will get recreated (The used borgbase role is not really idempotent and the borgbase API does not allow for filtering in their GraphQL API).
Once those are set `borgbackup_repository` will be defined automatically.

Furthermore the creation of the borgbase repository can be controlled via:
```
Expand Down
2 changes: 1 addition & 1 deletion defaults/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -37,4 +37,4 @@ borgbackup_bb_region: eu
# borgbackup_management_keys:
# - "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIElvcKplWycItag/MP7gYUCy95WIhMM1OFKbZ/j/ykFE adminuser"

borgbackup_auto_init: "{{ borgbackup_repository_server is defined }}"
borgbackup_auto_init: "{{ borgbackup_repository_server is defined or borgbackup_bb_repo is defined }}"
228 changes: 110 additions & 118 deletions library/borgbase.py
Original file line number Diff line number Diff line change
@@ -1,16 +1,16 @@
#!/usr/bin/python

DOCUMENTATION = '''
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 = '''
EXAMPLES = """
- name: Create new repository for server in EU with new SSH_key and quota
borgbase:
repository_name: "{{ inventory_hostname }}"
Expand All @@ -31,138 +31,130 @@
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.basic import AnsibleModule
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']
from ansible.module_utils.borgbase_api_client.mutations import SSH_ADD
from ansible.module_utils.borgbase_api_client.queries import KEY_DETAILS


REPO_ADD = """
mutation repoAdd(
$name: String
$quota: Int
$quotaEnabled: Boolean
$appendOnlyKeys: [String]
$fullAccessKeys: [String]
$alertDays: Int
$region: String
$borgVersion: String
) {
repoAdd(
name: $name
quota: $quota
quotaEnabled: $quotaEnabled
appendOnlyKeys: $appendOnlyKeys
fullAccessKeys: $fullAccessKeys
alertDays: $alertDays
region: $region
borgVersion: $borgVersion
) {
repoAdded {
id
name
repoPath
}
}
}
"""

REPO_DETAILS = """
query repoList {
repoList {
id
name
repoPath
}
}
"""


def get_or_create_ssh_key(client, module):
id = module.params["ssh_key"]
res = client.execute(KEY_DETAILS)
for i in res["data"]["sshList"]:
if i["keyData"] == id:
return i["id"], False

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
new_key_id = res["data"]["sshAdd"]["keyAdded"]["id"]
return new_key_id, True

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']
}

def get_or_create_repo(client, module, ssh_id):
name = module.params["repository_name"]
res = client.execute(REPO_DETAILS)
for i in res["data"]["repoList"]:
if i["name"] == name:
return i, False

if module.params["append_only"]:
access_level = "appendOnlyKeys"
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']
}
access_level = "fullAccessKeys"

new_repo_vars = {
"name": module.params["repository_name"],
"quotaEnabled": module.params["quota_enable"],
access_level: [ssh_id],
"alertDays": module.params["alertdays"],
"region": module.params["region"],
}
if module.params["quota_enable"]:
new_repo_vars["quota"] = 1000 * module.params["quota"]

res = client.execute(REPO_ADD, new_repo_vars)
return res
return res["data"]["repoAdd"]["repoAdded"], True


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'
)
)
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'])
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'])
# Setup information for Ansible
result = dict(changed=False, data="", type="")

# Add new repo using the key
res = add_repo(key_id)
try:
# Add new SSH key or get ID of old key
key_id, changed = get_or_create_ssh_key(client, module)

# Setup information for Ansible
result = dict(
changed = False,
data = '',
type = '',
key_id = ''
)
# Add new repo using the key
repo, changed = get_or_create_repo(client, module, 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
# Test for success and change info
result["changed"] = changed
result["data"] = repo
except Exception:
module.fail_json(msg="Failed creating new respository.", **result)
else:
module.exit_json(**result)


if __name__ == '__main__':
if __name__ == "__main__":
main()
16 changes: 1 addition & 15 deletions tasks/configure_borgbase.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,33 +5,19 @@
src: "{{ borgbackup_home }}/config/id_ssh_ed25519.pub"
register: slurped_key_b64

- name: Get repo URL from state-file
slurp:
src: "{{ borgbackup_home }}/data/borgbase_repo_info"
ignore_errors: yes
register: borgbase_repo_info

- name: Configure borgbase repository
local_action:
module: borgbase
repository_name: "{{ borgbackup_bb_repo }}"
token: "{{ borgbackup_bb_apikey }}"
new_ssh_key: yes
ssh_key: "{{ slurped_key_b64.content|b64decode }}"
append_only: "{{ borgbackup_append_only }}"
quota_enable: "{{ borgbackup_bb_quota is defined}}"
quota: "{{ borgbackup_bb_quota|default(omit) }}"
region: "{{ borgbackup_bb_region }}"
alertdays: "{{ borgbackup_bb_alertdays|default(omit) }}"
register: borgbase_repo_creation
when: borgbase_repo_info is failed

- name: Export borgbase variables
set_fact:
_repo_url: "{{ borgbase_repo_creation.data.repoPath if borgbase_repo_info is failed else borgbase_repo_info.content|b64decode }}"

- name: Write borgbase repo info
copy:
dest: "{{ borgbackup_home }}/data/borgbase_repo_info"
content: "{{ _repo_url }}"

_repo_url: "{{ borgbase_repo_creation.data.repoPath }}"

0 comments on commit e4d1e76

Please sign in to comment.