Add basic client for Rundeck
Change-Id: I4b1a8deedb858ec664d4f888ef78458bd19f102f
diff --git a/_modules/rundeck.py b/_modules/rundeck.py
new file mode 100644
index 0000000..9d53361
--- /dev/null
+++ b/_modules/rundeck.py
@@ -0,0 +1,117 @@
+import logging
+
+import salt.exceptions
+
+import requests
+from requests.compat import urljoin
+
+LOG = logging.getLogger(__name__)
+
+
+def get_project(name):
+ session, make_url = get_session()
+ resp = session.get(make_url("/api/18/project/{}".format(name)))
+ status_code = resp.status_code
+ if status_code == 200:
+ return resp.json()
+ elif status_code == 404:
+ return None
+ raise salt.exceptions.SaltInvocationError(
+ "Could not retrieve information about project {} from Rundeck {}: {}"
+ .format(name, make_url.base_url, status_code))
+
+
+def create_project(name, params):
+ session, make_url = get_session()
+ config = create_project_config(name, params)
+ LOG.debug("create_project: %s", name)
+ LOG.warning("create_project.config: %s/%s", name, config)
+ resp = session.post(
+ make_url("/api/18/projects"),
+ json={
+ 'name': name,
+ 'config': config,
+ },
+ allow_redirects=False,
+ )
+ if resp.status_code == 201:
+ return resp.json()
+ LOG.debug("create_project: %s", name)
+
+
+def create_project_config(name, params, config=None):
+ config = dict(config) if config else {}
+ if params['description']:
+ config['project.description'] = params['description']
+ else:
+ config.pop('project.description', None)
+ config.update({
+ 'resources.source.1.config.file':
+ "/var/rundeck/projects/{}/etc/resources.yaml".format(name),
+ 'resources.source.1.config.format': 'resourceyaml',
+ 'resources.source.1.config.generateFileAutomatically': 'true',
+ 'resources.source.1.config.includeServerNode': 'false',
+ 'resources.source.1.config.requireFileExists': 'false',
+ 'project.ssh-keypath': '/var/rundeck/.ssh/id_rsa',
+ 'resources.source.1.type': 'file',
+ })
+ return config
+
+
+def update_project_config(name, project, config):
+ session, make_url = get_session()
+ resp = session.put(
+ make_url("/api/18/project/{}/config".format(name)),
+ json=config,
+ allow_redirects=False,
+ )
+ if resp.status_code == 201:
+ return resp.json()
+ LOG.debug("update_project: %s", name)
+
+
+def delete_project(name):
+ session, make_url = get_session()
+ resp = session.delete(make_url("/api/18/project/{}".format(name)))
+ status_code = resp.status_code
+ if status_code != 204:
+ raise salt.exceptions.SaltInvocationError(
+ "Could not remove project {} from Rundeck {}: {}"
+ .format(name, make_url.base_url, status_code))
+
+
+def get_session():
+ def make_url(url):
+ return urljoin(make_url.base_url, url)
+
+ rundeck_url = __salt__['config.get']('rundeck.url')
+ make_url.base_url = rundeck_url
+
+ api_token = __salt__['config.get']('rundeck.api_token')
+ username = __salt__['config.get']('rundeck.username')
+ password = __salt__['config.get']('rundeck.password')
+
+ session = requests.Session()
+
+ if api_token:
+ session.headers.update({
+ 'Content-Type': 'application/json',
+ 'X-Rundeck-Auth-Token': api_token,
+ })
+ else:
+ resp = session.post(make_url('/j_security_check'),
+ data={
+ 'j_username': username,
+ 'j_password': password,
+ },
+ )
+ if (resp.status_code != 200 or
+ '/user/error' in resp.url or
+ '/user/login' in resp.url):
+ raise salt.exceptions.SaltInvocationError(
+ "Username/passowrd authorization failed in Rundeck {} for "
+ "user {}".format(rundeck_url, username))
+ session.params.update({
+ 'format': 'json',
+ })
+ return session, make_url