Merge "Update .travis.yml and .kitchen.yml files for parallel testing"
diff --git a/README.rst b/README.rst
index 80cd57d..0619d82 100644
--- a/README.rst
+++ b/README.rst
@@ -205,6 +205,16 @@
salt-call event.send 'salt/orchestrate/start' "{'orchestrate': 'salt/orchestrate/infra_install.sls'}"
+Synchronise modules and pillars on minion start.
+
+.. code-block:: yaml
+
+ salt:
+ master:
+ reactor:
+ 'salt/minion/*/start':
+ - salt://salt/reactor/minion_start.sls
+
Add and/or remove the minion key
.. code-block:: yaml
diff --git a/_modules/saltkey.py b/_modules/saltkey.py
new file mode 100644
index 0000000..97dc5c9
--- /dev/null
+++ b/_modules/saltkey.py
@@ -0,0 +1,106 @@
+from __future__ import absolute_import
+
+# Import python libs
+import logging
+import os
+
+try:
+ import paramiko
+ HAS_PARAMIKO = True
+except:
+ HAS_PARAMIKO = False
+
+# Import Salt libs
+import salt.config
+import salt.wheel
+
+LOG = logging.getLogger(__name__)
+
+
+def __virtual__():
+ '''
+ Only load if paramiko library exist.
+ '''
+ if not HAS_PARAMIKO:
+ return (
+ False,
+ 'Can not load module saltkey: paramiko library not found')
+ return True
+
+
+def key_create(id_, host, force=False):
+ '''
+ Generates minion keypair, accepts it on master and injects it to minion via SSH.
+
+ CLI Examples:
+
+ .. code-block:: bash
+
+ salt-call saltkey.key_create <MINION_ID> <MINION_IP_ADDRESS> force=False
+ '''
+ ret = {
+ 'retcode': 0,
+ 'msg': 'Salt Key for minion %s is already accepted' % id_,
+ }
+
+ opts = salt.config.master_config('/etc/salt/master')
+ wheel = salt.wheel.WheelClient(opts)
+ keys = wheel.cmd('key.gen_accept', arg=[id_], kwarg={'force': force})
+ pub_key = keys.get('pub', None)
+ priv_key = keys.get('priv', None)
+
+ if pub_key and priv_key:
+ ssh = paramiko.SSHClient()
+ ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
+ # Establish SSH connection to minion
+ try:
+ ssh.connect(host)
+ except paramiko.ssh_exception.AuthenticationException:
+ msg = ('Could not establish SSH connection to minion "%s" on address %s, please ensure '
+ 'that current user\'s SSH key is present in minions authorized_keys.') % (id_, host)
+ LOG.error(msg)
+ ret['retcode'] = 1
+ ret['msg'] = msg
+ wheel.cmd_async({'fun': 'key.delete', 'match': id_})
+ return ret
+ except Exception as e:
+ msg = ('Unknown error occured while establishing SSH connection '
+ 'to minion "%s" on address %s: %s') % (id_, host, repr(e))
+ LOG.error(msg)
+ ret['retcode'] = 1
+ ret['msg'] = msg
+ wheel.cmd_async({'fun': 'key.delete', 'match': id_})
+ return ret
+ # Setup the keys on minion side the ugly way, nice one didn't work
+ key_path = '/etc/salt/pki/minion'
+ command = ('echo "%(pub_key)s" > %(pub_path)s && chmod 644 %(pub_path)s && '
+ 'echo "%(priv_key)s" > %(priv_path)s && chmod 400 %(priv_path)s && '
+ 'salt-call --local service.restart salt-minion') % {
+ 'pub_path': os.path.join(key_path, 'minion.pub'),
+ 'pub_key': pub_key,
+ 'priv_path': os.path.join(key_path, 'minion.pem'),
+ 'priv_key': priv_key
+ }
+
+ ssh_chan = ssh.get_transport().open_session()
+ ssh_chan.exec_command(command)
+ # Wait for command return
+ while True:
+ if ssh_chan.exit_status_ready():
+ exit_status = ssh_chan.recv_exit_status()
+ stderr = ssh_chan.recv_stderr(1000)
+ stdout = ssh_chan.recv(1000)
+ break
+ ssh.close()
+ # Evaluate SSH command exit status
+ if exit_status != 0:
+ msg = 'Keypair injection to Salt minion failed on target with following error: %s' % stderr
+ LOG.error(msg)
+ ret['retcode'] = exit_status
+ ret['msg'] = msg
+ return ret
+
+ ret['msg'] = 'Salt Key successfully created'
+
+ return ret
+
diff --git a/metadata/service/master/reactor/minion_start.yml b/metadata/service/master/reactor/minion_start.yml
new file mode 100644
index 0000000..cbe41d9
--- /dev/null
+++ b/metadata/service/master/reactor/minion_start.yml
@@ -0,0 +1,6 @@
+parameters:
+ salt:
+ master:
+ reactor:
+ 'salt/minion/*/start':
+ - salt://salt/reactor/minion_start.sls
diff --git a/salt/api.sls b/salt/api.sls
index 61e5687..2d7ac5a 100644
--- a/salt/api.sls
+++ b/salt/api.sls
@@ -15,6 +15,20 @@
- watch_in:
- service: salt_api_service
+{%- if api.get('ssl', {}).authority is defined %}
+
+{%- set cert_file = "/etc/ssl/certs/" + api.ssl.get('name', grains.id) + ".crt" %}
+{%- set ca_file = "/etc/ssl/certs/ca-" + api.ssl.authority + ".crt" %}
+
+salt_api_init_tls:
+ cmd.run:
+ - name: "cat {{ cert_file }} {{ ca_file }} > /etc/ssl/certs/{{ api.ssl.get('name', grains.id) }}-chain.crt"
+ - creates: /etc/ssl/certs/{{ api.ssl.get('name', grains.id) }}-chain.crt
+ - watch_in:
+ - service: salt_api_service
+
+{%- endif %}
+
salt_api_service:
service.running:
- name: salt-api
@@ -23,4 +37,4 @@
- watch:
- file: /etc/salt/master.d/_api.conf
-{%- endif %}
+{%- endif %}
\ No newline at end of file
diff --git a/salt/files/_api.conf b/salt/files/_api.conf
index a1e2368..26856f8 100644
--- a/salt/files/_api.conf
+++ b/salt/files/_api.conf
@@ -9,8 +9,11 @@
ssl_crt: /etc/letsencrypt/live/{{ api.ssl.name }}/cert.pem
ssl_key: /etc/letsencrypt/live/{{ api.ssl.name }}/privkey.pem
{%- elif api.ssl.engine == 'salt' %}
- ssl_crt: /etc/ssl/certs/{{ system.name }}.{{ system.domain }}.crt
- ssl_key: /etc/ssl/private/{{ system.name }}.{{ system.domain }}.key
+ ssl_crt: /etc/ssl/certs/{{ api.ssl.get('name', grains.id) }}.crt
+ ssl_key: /etc/ssl/private/{{ api.ssl.get('name', grains.id) }}.key
+ {%- if api.ssl.authority is defined %}
+ ssl_chain: /etc/ssl/certs/{{ api.ssl.get('name', grains.id) }}-chain.crt
+ {%- endif %}
{%- else %}
ssl_crt: {{ api.ssl.get('cert_file')|default("/etc/ssl/certs/"+grains.get('fqdn')+".crt") }}
ssl_key: {{ api.ssl.get('key_file')|default("/etc/ssl/private/"+grains.get('fqdn')+".key") }}
@@ -25,3 +28,4 @@
{#-
vim: syntax=jinja
-#}
+
diff --git a/salt/reactor/node_start.sls b/salt/reactor/minion_start.sls
similarity index 60%
rename from salt/reactor/node_start.sls
rename to salt/reactor/minion_start.sls
index 904822c..f652b5b 100644
--- a/salt/reactor/node_start.sls
+++ b/salt/reactor/minion_start.sls
@@ -1,8 +1,10 @@
-node_sync_all:
+minion_sync_all:
local.saltutil.sync_all:
- tgt: {{ data.id }}
+ - queue: True
-node_refresh_pillar:
+minion_refresh_pillar:
local.saltutil.refresh_pillar:
- tgt: {{ data.id }}
+ - queue: True