Merge "Add pgpass file for Maas DB"
diff --git a/README.rst b/README.rst
index 6b3548e..315534d 100644
--- a/README.rst
+++ b/README.rst
@@ -151,6 +151,52 @@
         - 'ssh-rsa ASDFOSADFISdfasdfasjdklfjasdJFASDJfASdf923@AAAAB3NzaC1yc2EAAAADAQABAAACAQCv8ISOESGgYUOycYw1SAs/SfHTqtSCTephD/7o2+mEZO53xN98sChiFscFaPA2ZSMoZbJ6MQLKcWKMK2OaTdNSAvn4UE4T6VP0ccdumHDNRwO3f6LptvXr9NR5Wocz2KAgptk+uaA8ytM0Aj9NT0UlfjAXkKnoKyNq6yG+lx4HpwolVaFSlqRXf/iuHpCrspv/u1NW7ReMElJoXv+0zZ7Ow0ZylISdYkaqbV8QatCb17v1+xX03xLsZigfugce/8CDsibSYvJv+Hli5CCBsKgfFqLy4R5vGxiLSVzG/asdjalskjdlkasjdasd/asdajsdkjalaksdjfasd/fa/sdf/asd/fas/dfsadf blah@blah'
 
 
+
+Usage of local repos
+
+.. code-block:: yaml
+
+  maas:
+    cluster:
+      enabled: true
+      region:
+        port: 80
+        host: localhost
+      saltstack_repo_key: |
+        -----BEGIN PGP PUBLIC KEY BLOCK-----
+        Version: GnuPG v2
+
+        mQENBFOpvpgBCADkP656H41i8fpplEEB8IeLhugyC2rTEwwSclb8tQNYtUiGdna9
+        m38kb0OS2DDrEdtdQb2hWCnswxaAkUunb2qq18vd3dBvlnI+C4/xu5ksZZkRj+fW
+        tArNR18V+2jkwcG26m8AxIrT+m4M6/bgnSfHTBtT5adNfVcTHqiT1JtCbQcXmwVw
+        WbqS6v/LhcsBE//SHne4uBCK/GHxZHhQ5jz5h+3vWeV4gvxS3Xu6v1IlIpLDwUts
+        kT1DumfynYnnZmWTGc6SYyIFXTPJLtnoWDb9OBdWgZxXfHEcBsKGha+bXO+m2tHA
+        gNneN9i5f8oNxo5njrL8jkCckOpNpng18BKXABEBAAG0MlNhbHRTdGFjayBQYWNr
+        YWdpbmcgVGVhbSA8cGFja2FnaW5nQHNhbHRzdGFjay5jb20+iQE4BBMBAgAiBQJT
+        qb6YAhsDBgsJCAcDAgYVCAIJCgsEFgIDAQIeAQIXgAAKCRAOCKFJ3le/vhkqB/0Q
+        WzELZf4d87WApzolLG+zpsJKtt/ueXL1W1KA7JILhXB1uyvVORt8uA9FjmE083o1
+        yE66wCya7V8hjNn2lkLXboOUd1UTErlRg1GYbIt++VPscTxHxwpjDGxDB1/fiX2o
+        nK5SEpuj4IeIPJVE/uLNAwZyfX8DArLVJ5h8lknwiHlQLGlnOu9ulEAejwAKt9CU
+        4oYTszYM4xrbtjB/fR+mPnYh2fBoQO4d/NQiejIEyd9IEEMd/03AJQBuMux62tjA
+        /NwvQ9eqNgLw9NisFNHRWtP4jhAOsshv1WW+zPzu3ozoO+lLHixUIz7fqRk38q8Q
+        9oNR31KvrkSNrFbA3D89uQENBFOpvpgBCADJ79iH10AfAfpTBEQwa6vzUI3Eltqb
+        9aZ0xbZV8V/8pnuU7rqM7Z+nJgldibFk4gFG2bHCG1C5aEH/FmcOMvTKDhJSFQUx
+        uhgxttMArXm2c22OSy1hpsnVG68G32Nag/QFEJ++3hNnbyGZpHnPiYgej3FrerQJ
+        zv456wIsxRDMvJ1NZQB3twoCqwapC6FJE2hukSdWB5yCYpWlZJXBKzlYz/gwD/Fr
+        GL578WrLhKw3UvnJmlpqQaDKwmV2s7MsoZogC6wkHE92kGPG2GmoRD3ALjmCvN1E
+        PsIsQGnwpcXsRpYVCoW7e2nW4wUf7IkFZ94yOCmUq6WreWI4NggRcFC5ABEBAAGJ
+        AR8EGAECAAkFAlOpvpgCGwwACgkQDgihSd5Xv74/NggA08kEdBkiWWwJZUZEy7cK
+        WWcgjnRuOHd4rPeT+vQbOWGu6x4bxuVf9aTiYkf7ZjVF2lPn97EXOEGFWPZeZbH4
+        vdRFH9jMtP+rrLt6+3c9j0M8SIJYwBL1+CNpEC/BuHj/Ra/cmnG5ZNhYebm76h5f
+        T9iPW9fFww36FzFka4VPlvA4oB7ebBtquFg3sdQNU/MmTVV4jPFWXxh4oRDDR+8N
+        1bcPnbB11b5ary99F/mqr7RgQ+YFF0uKRE3SKa7a+6cIuHEZ7Za+zhPaQlzAOZlx
+        fuBmScum8uQTrEF5+Um5zkwC7EXTdH1co/+/V/fpOtxIg4XO4kcugZefVm5ERfVS
+        MA==
+        =dtMN
+        -----END PGP PUBLIC KEY BLOCK-----
+      saltstack_repo_xenial: "http://${_param:local_repo_url}/ubuntu-xenial stable salt"
+      saltstack_repo_trusty: "http://${_param:local_repo_url}/ubuntu-trusty stable salt"
+
 Single MAAS cluster service [multiple racks]
 
 .. code-block:: yaml
@@ -160,10 +206,64 @@
         enabled: true
         role: master/slave
 
+.. code-block:: yaml
+
+    maas:
+      cluster:
+        enabled: true
+        role: master/slave
+
+Module function's example:
+==========================
+
+* Wait for status of selected machine's:
+
+.. code-block:: bash
+
+    > cat maas/machines/wait_for_machines_ready.sls
+
+    ...
+
+    wait_for_machines_ready:
+      module.run:
+      - name: maas.wait_for_machine_status
+      - kwargs:
+            machines:
+              - kvm01
+              - kvm02
+            timeout: 1200 # in seconds
+            req_status: "Ready"
+      - require:
+        - cmd: maas_login_admin
+      ...
+
+If module run w/\o any extra paremeters - `wait_for_machines_ready` will wait for defined in salt machines. In those case, will be usefull to skip some machines:
+
+.. code-block:: bash
+
+    > cat maas/machines/wait_for_machines_deployed.sls
+
+    ...
+
+    wait_for_machines_ready:
+      module.run:
+      - name: maas.wait_for_machine_status
+      - kwargs:
+            timeout: 1200 # in seconds
+            req_status: "deployed"
+            ignore_machines:
+               - kvm01 # in case it's broken or whatever
+      - require:
+        - cmd: maas_login_admin
+      ...
+
+List of avaibled `req_status` defined in global variable:
+
+
 Read more
 =========
 
-* 
+* https://maas.io/
 
 Documentation and Bugs
 ======================
diff --git a/_modules/maas.py b/_modules/maas.py
index e545a53..c5029a7 100644
--- a/_modules/maas.py
+++ b/_modules/maas.py
@@ -13,15 +13,15 @@
 
 from __future__ import absolute_import
 
-import io
-import logging
 import collections
-import os.path
-import subprocess
-import urllib2
+import copy
 import hashlib
-
+import io
 import json
+import logging
+import os.path
+import time
+import urllib2
 
 LOG = logging.getLogger(__name__)
 
@@ -46,6 +46,14 @@
 
 APIKEY_FILE = '/var/lib/maas/.maas_credentials'
 
+STATUS_NAME_DICT = dict([
+    (0, 'New'), (1, 'Commissioning'), (2, 'Failed commissioning'),
+    (3, 'Missing'), (4, 'Ready'), (5, 'Reserved'), (10, 'Allocated'),
+    (9, 'Deploying'), (6, 'Deployed'), (7, 'Retired'), (8, 'Broken'),
+    (11, 'Failed deployment'), (12, 'Releasing'),
+    (13, 'Releasing failed'), (14, 'Disk erasing'),
+    (15, 'Failed disk erasing')])
+
 
 def _format_data(data):
     class Lazy:
@@ -407,7 +415,7 @@
         if machine['status'] == self.DEPLOYED:
             return
         if machine['status'] != self.READY:
-            raise Exception('Not in ready state')
+            raise Exception('Machine:{} not in READY state'.format(name))
         if 'ip' not in interface:
             return
         data = {
@@ -424,6 +432,7 @@
 
 
 class DeployMachines(MaasObject):
+    # FIXME
     READY = 4
     DEPLOYED = 6
 
@@ -654,13 +663,6 @@
         result = cls._maas.get(u'api/2.0/machines/')
         json_result = json.loads(result.read())
         res = []
-        status_name_dict = dict([
-            (0, 'New'), (1, 'Commissioning'), (2, 'Failed commissioning'),
-            (3, 'Missing'), (4, 'Ready'), (5, 'Reserved'), (10, 'Allocated'),
-            (9, 'Deploying'), (6, 'Deployed'), (7, 'Retired'), (8, 'Broken'),
-            (11, 'Failed deployment'), (12, 'Releasing'),
-            (13, 'Releasing failed'), (14, 'Disk erasing'),
-            (15, 'Failed disk erasing')])
         summary = collections.Counter()
         if objects_name:
             if ',' in objects_name:
@@ -670,13 +672,74 @@
         for machine in json_result:
             if objects_name and machine['hostname'] not in objects_name:
                 continue
-            status = status_name_dict[machine['status']]
+            status = STATUS_NAME_DICT[machine['status'].lower()]
             summary[status] += 1
-            res.append('hostname:{},system_id:{},status:{}'
-                       .format(machine['hostname'], machine['system_id'],
-                               status))
+            res.append(
+                {'hostname': machine['hostname'],
+                 'system_id': machine['system_id'],
+                 'status': status})
         return {'machines': res, 'summary': summary}
 
+    @classmethod
+    def wait_for_machine_status(cls, **kwargs):
+        """
+        A function that wait for any requested status, for any set of maas
+        machines.
+
+        If no kwargs has been passed - will try to wait ALL
+        defined in salt::maas::region::machines
+
+        See readme file for more examples.
+        CLI Example:
+        .. code-block:: bash
+
+            salt-call state.apply maas.machines.wait_for_deployed
+
+        :param kwargs:
+            timeout:    in s; Global timeout for wait
+            poll_time:  in s;Sleep time, between retry
+            req_status: string; Polling status
+            machines:   list; machine names
+            ignore_machines: list; machine names
+        :ret: True
+                 Exception - if something fail/timeout reached
+        """
+        timeout = kwargs.get("timeout", 60 * 120)
+        poll_time = kwargs.get("poll_time", 30)
+        req_status = kwargs.get("req_status", "Ready")
+        to_discover = kwargs.get("machines", None)
+        ignore_machines = kwargs.get("ignore_machines", None)
+        if not to_discover:
+            try:
+                to_discover = __salt__['config.get']('maas')['region'][
+                    'machines'].keys()
+            except KeyError:
+                LOG.warning("No defined machines!")
+                return True
+        total = copy.deepcopy(to_discover) or []
+        if ignore_machines and total:
+            total = [x for x in to_discover if x not in ignore_machines]
+        started_at = time.time()
+        while len(total) <= len(to_discover):
+            for m in to_discover:
+                for discovered in MachinesStatus.execute()['machines']:
+                    if m == discovered['hostname'] and \
+                                    discovered['status'] == req_status.lower():
+                        if m in total: total.remove(m)
+            if len(total) <= 0:
+                LOG.debug(
+                    "Machines:{} are:{}".format(to_discover, req_status))
+                return True
+            if (timeout - (time.time() - started_at)) <= 0:
+                raise Exception(
+                    'Machines:{}not in {} state'.format(total, req_status))
+            LOG.info(
+                "Waiting status:{} "
+                "for machines:{}"
+                "\nsleep for:{}s "
+                "Timeout:{}s".format(req_status, total, poll_time, timeout))
+            time.sleep(poll_time)
+
 
 def process_fabrics():
     return Fabric().process()
@@ -732,3 +795,7 @@
 
 def process_sshprefs():
     return SSHPrefs().process()
+
+
+def wait_for_machine_status(**kwargs):
+    return MachinesStatus.wait_for_machine_status(**kwargs)
diff --git a/maas/files/curtin_userdata_amd64_generic_trusty b/maas/files/curtin_userdata_amd64_generic_trusty
index bc8494f..1ff17dd 100644
--- a/maas/files/curtin_userdata_amd64_generic_trusty
+++ b/maas/files/curtin_userdata_amd64_generic_trusty
@@ -1,4 +1,4 @@
-{%- from "maas/map.jinja" import server with context %}
+{%- from "maas/map.jinja" import cluster with context %}
 {% raw %}
 #cloud-config
 debconf_selections:
@@ -17,8 +17,13 @@
 {{endif}}
 late_commands:
   maas: [wget, '--no-proxy', {{node_disable_pxe_url|escape.json}}, '--post-data', {{node_disable_pxe_data|escape.json}}, '-O', '/dev/null']
-  apt_00_set_repo: ["curtin", "in-target", "--", "sh", "-c", "echo 'deb [arch=amd64] http://repo.saltstack.com/apt/ubuntu/14.04/amd64/2016.3/ trusty main' >> /etc/apt/sources.list"]
-  apt_01_set_gpg: ["curtin", "in-target", "--", "sh", "-c", "echo 'LS0tLS1CRUdJTiBQR1AgUFVCTElDIEtFWSBCTE9DSy0tLS0tClZlcnNpb246IEdudVBHIHYyCgptUUVOQkZPcHZwZ0JDQURrUDY1Nkg0MWk4ZnBwbEVFQjhJZUxodWd5QzJyVEV3d1NjbGI4dFFOWXRVaUdkbmE5Cm0zOGtiME9TMkREckVkdGRRYjJoV0Nuc3d4YUFrVXVuYjJxcTE4dmQzZEJ2bG5JK0M0L3h1NWtzWlprUmorZlcKdEFyTlIxOFYrMmprd2NHMjZtOEF4SXJUK200TTYvYmduU2ZIVEJ0VDVhZE5mVmNUSHFpVDFKdENiUWNYbXdWdwpXYnFTNnYvTGhjc0JFLy9TSG5lNHVCQ0svR0h4WkhoUTVqejVoKzN2V2VWNGd2eFMzWHU2djFJbElwTER3VXRzCmtUMUR1bWZ5bllublptV1RHYzZTWXlJRlhUUEpMdG5vV0RiOU9CZFdnWnhYZkhFY0JzS0doYStiWE8rbTJ0SEEKZ05uZU45aTVmOG9OeG81bmpyTDhqa0Nja09wTnBuZzE4QktYQUJFQkFBRzBNbE5oYkhSVGRHRmpheUJRWVdOcgpZV2RwYm1jZ1ZHVmhiU0E4Y0dGamEyRm5hVzVuUUhOaGJIUnpkR0ZqYXk1amIyMCtpUUU0QkJNQkFnQWlCUUpUCnFiNllBaHNEQmdzSkNBY0RBZ1lWQ0FJSkNnc0VGZ0lEQVFJZUFRSVhnQUFLQ1JBT0NLRkozbGUvdmhrcUIvMFEKV3pFTFpmNGQ4N1dBcHpvbExHK3pwc0pLdHQvdWVYTDFXMUtBN0pJTGhYQjF1eXZWT1J0OHVBOUZqbUUwODNvMQp5RTY2d0N5YTdWOGhqTm4ybGtMWGJvT1VkMVVURXJsUmcxR1liSXQrK1ZQc2NUeEh4d3BqREd4REIxL2ZpWDJvCm5LNVNFcHVqNEllSVBKVkUvdUxOQXdaeWZYOERBckxWSjVoOGxrbndpSGxRTEdsbk91OXVsRUFlandBS3Q5Q1UKNG9ZVHN6WU00eHJidGpCL2ZSK21QblloMmZCb1FPNGQvTlFpZWpJRXlkOUlFRU1kLzAzQUpRQnVNdXg2MnRqQQovTnd2UTllcU5nTHc5TmlzRk5IUld0UDRqaEFPc3NodjFXVyt6UHp1M296b08rbExIaXhVSXo3ZnFSazM4cThRCjlvTlIzMUt2cmtTTnJGYkEzRDg5dVFFTkJGT3B2cGdCQ0FESjc5aUgxMEFmQWZwVEJFUXdhNnZ6VUkzRWx0cWIKOWFaMHhiWlY4Vi84cG51VTdycU03WituSmdsZGliRms0Z0ZHMmJIQ0cxQzVhRUgvRm1jT012VEtEaEpTRlFVeAp1aGd4dHRNQXJYbTJjMjJPU3kxaHBzblZHNjhHMzJOYWcvUUZFSisrM2hObmJ5R1pwSG5QaVlnZWozRnJlclFKCnp2NDU2d0lzeFJETXZKMU5aUUIzdHdvQ3F3YXBDNkZKRTJodWtTZFdCNXlDWXBXbFpKWEJLemxZei9nd0QvRnIKR0w1NzhXckxoS3czVXZuSm1scHFRYURLd21WMnM3TXNvWm9nQzZ3a0hFOTJrR1BHMkdtb1JEM0FMam1Ddk4xRQpQc0lzUUdud3BjWHNScFlWQ29XN2Uyblc0d1VmN0lrRlo5NHlPQ21VcTZXcmVXSTROZ2dSY0ZDNUFCRUJBQUdKCkFSOEVHQUVDQUFrRkFsT3B2cGdDR3d3QUNna1FEZ2loU2Q1WHY3NC9OZ2dBMDhrRWRCa2lXV3dKWlVaRXk3Y0sKV1djZ2puUnVPSGQ0clBlVCt2UWJPV0d1Nng0Ynh1VmY5YVRpWWtmN1pqVkYybFBuOTdFWE9FR0ZXUFplWmJINAp2ZFJGSDlqTXRQK3JyTHQ2KzNjOWowTThTSUpZd0JMMStDTnBFQy9CdUhqL1JhL2Ntbkc1Wk5oWWVibTc2aDVmClQ5aVBXOWZGd3czNkZ6RmthNFZQbHZBNG9CN2ViQnRxdUZnM3NkUU5VL01tVFZWNGpQRldYeGg0b1JERFIrOE4KMWJjUG5iQjExYjVhcnk5OUYvbXFyN1JnUStZRkYwdUtSRTNTS2E3YSs2Y0l1SEVaN1phK3poUGFRbHpBT1pseApmdUJtU2N1bTh1UVRyRUY1K1VtNXprd0M3RVhUZEgxY28vKy9WL2ZwT3R4SWc0WE80a2N1Z1plZlZtNUVSZlZTCk1BPT0KPWR0TU4KLS0tLS1FTkQgUEdQIFBVQkxJQyBLRVkgQkxPQ0stLS0tLQo='|base64 -d|apt-key add -"]
+{% endraw %}
+{%- if not cluster.saltstack_repo_key == 'none' %}
+{% set salt_repo_key = salt['hashutil.base64_b64encode'](cluster.saltstack_repo_key) %}
+  apt_00_set_gpg: ["curtin", "in-target", "--", "sh", "-c", "echo '{{salt_repo_key}}' | base64 -d | apt-key add -"]
+{%- endif %}
+  apt_01_set_repo: ["curtin", "in-target", "--", "sh", "-c", "echo 'deb [arch=amd64] {{ cluster.saltstack_repo_trusty }}' >> /etc/apt/sources.list"]
+{% raw %}
   apt_03_update: ["curtin", "in-target", "--", "apt-get", "update"]
   salt_01_install: ["curtin", "in-target", "--", "apt-get", "-y", "install", "salt-minion"]
 {% endraw %}
@@ -35,4 +40,4 @@
   driver_06_depmod: ["curtin", "in-target", "--", "depmod"]
   driver_07_update_initramfs: ["curtin", "in-target", "--", "update-initramfs", "-u"]
 {{endif}}
-{% endraw %}
+{% endraw %}
\ No newline at end of file
diff --git a/maas/files/curtin_userdata_amd64_generic_xenial b/maas/files/curtin_userdata_amd64_generic_xenial
index e645593..55e0901 100644
--- a/maas/files/curtin_userdata_amd64_generic_xenial
+++ b/maas/files/curtin_userdata_amd64_generic_xenial
@@ -1,4 +1,4 @@
-{%- from "maas/map.jinja" import server with context %}
+{%- from "maas/map.jinja" import cluster with context %}
 {% raw %}
 #cloud-config
 debconf_selections:
@@ -17,8 +17,13 @@
 {{endif}}
 late_commands:
   maas: [wget, '--no-proxy', {{node_disable_pxe_url|escape.json}}, '--post-data', {{node_disable_pxe_data|escape.json}}, '-O', '/dev/null']
-  apt_00_set_repo: ["curtin", "in-target", "--", "sh", "-c", "echo 'deb [arch=amd64] http://repo.saltstack.com/apt/ubuntu/16.04/amd64/2016.3/ xenial main' >> /etc/apt/sources.list"]
-  apt_01_set_gpg: ["curtin", "in-target", "--", "sh", "-c", "echo 'LS0tLS1CRUdJTiBQR1AgUFVCTElDIEtFWSBCTE9DSy0tLS0tClZlcnNpb246IEdudVBHIHYyCgptUUVOQkZPcHZwZ0JDQURrUDY1Nkg0MWk4ZnBwbEVFQjhJZUxodWd5QzJyVEV3d1NjbGI4dFFOWXRVaUdkbmE5Cm0zOGtiME9TMkREckVkdGRRYjJoV0Nuc3d4YUFrVXVuYjJxcTE4dmQzZEJ2bG5JK0M0L3h1NWtzWlprUmorZlcKdEFyTlIxOFYrMmprd2NHMjZtOEF4SXJUK200TTYvYmduU2ZIVEJ0VDVhZE5mVmNUSHFpVDFKdENiUWNYbXdWdwpXYnFTNnYvTGhjc0JFLy9TSG5lNHVCQ0svR0h4WkhoUTVqejVoKzN2V2VWNGd2eFMzWHU2djFJbElwTER3VXRzCmtUMUR1bWZ5bllublptV1RHYzZTWXlJRlhUUEpMdG5vV0RiOU9CZFdnWnhYZkhFY0JzS0doYStiWE8rbTJ0SEEKZ05uZU45aTVmOG9OeG81bmpyTDhqa0Nja09wTnBuZzE4QktYQUJFQkFBRzBNbE5oYkhSVGRHRmpheUJRWVdOcgpZV2RwYm1jZ1ZHVmhiU0E4Y0dGamEyRm5hVzVuUUhOaGJIUnpkR0ZqYXk1amIyMCtpUUU0QkJNQkFnQWlCUUpUCnFiNllBaHNEQmdzSkNBY0RBZ1lWQ0FJSkNnc0VGZ0lEQVFJZUFRSVhnQUFLQ1JBT0NLRkozbGUvdmhrcUIvMFEKV3pFTFpmNGQ4N1dBcHpvbExHK3pwc0pLdHQvdWVYTDFXMUtBN0pJTGhYQjF1eXZWT1J0OHVBOUZqbUUwODNvMQp5RTY2d0N5YTdWOGhqTm4ybGtMWGJvT1VkMVVURXJsUmcxR1liSXQrK1ZQc2NUeEh4d3BqREd4REIxL2ZpWDJvCm5LNVNFcHVqNEllSVBKVkUvdUxOQXdaeWZYOERBckxWSjVoOGxrbndpSGxRTEdsbk91OXVsRUFlandBS3Q5Q1UKNG9ZVHN6WU00eHJidGpCL2ZSK21QblloMmZCb1FPNGQvTlFpZWpJRXlkOUlFRU1kLzAzQUpRQnVNdXg2MnRqQQovTnd2UTllcU5nTHc5TmlzRk5IUld0UDRqaEFPc3NodjFXVyt6UHp1M296b08rbExIaXhVSXo3ZnFSazM4cThRCjlvTlIzMUt2cmtTTnJGYkEzRDg5dVFFTkJGT3B2cGdCQ0FESjc5aUgxMEFmQWZwVEJFUXdhNnZ6VUkzRWx0cWIKOWFaMHhiWlY4Vi84cG51VTdycU03WituSmdsZGliRms0Z0ZHMmJIQ0cxQzVhRUgvRm1jT012VEtEaEpTRlFVeAp1aGd4dHRNQXJYbTJjMjJPU3kxaHBzblZHNjhHMzJOYWcvUUZFSisrM2hObmJ5R1pwSG5QaVlnZWozRnJlclFKCnp2NDU2d0lzeFJETXZKMU5aUUIzdHdvQ3F3YXBDNkZKRTJodWtTZFdCNXlDWXBXbFpKWEJLemxZei9nd0QvRnIKR0w1NzhXckxoS3czVXZuSm1scHFRYURLd21WMnM3TXNvWm9nQzZ3a0hFOTJrR1BHMkdtb1JEM0FMam1Ddk4xRQpQc0lzUUdud3BjWHNScFlWQ29XN2Uyblc0d1VmN0lrRlo5NHlPQ21VcTZXcmVXSTROZ2dSY0ZDNUFCRUJBQUdKCkFSOEVHQUVDQUFrRkFsT3B2cGdDR3d3QUNna1FEZ2loU2Q1WHY3NC9OZ2dBMDhrRWRCa2lXV3dKWlVaRXk3Y0sKV1djZ2puUnVPSGQ0clBlVCt2UWJPV0d1Nng0Ynh1VmY5YVRpWWtmN1pqVkYybFBuOTdFWE9FR0ZXUFplWmJINAp2ZFJGSDlqTXRQK3JyTHQ2KzNjOWowTThTSUpZd0JMMStDTnBFQy9CdUhqL1JhL2Ntbkc1Wk5oWWVibTc2aDVmClQ5aVBXOWZGd3czNkZ6RmthNFZQbHZBNG9CN2ViQnRxdUZnM3NkUU5VL01tVFZWNGpQRldYeGg0b1JERFIrOE4KMWJjUG5iQjExYjVhcnk5OUYvbXFyN1JnUStZRkYwdUtSRTNTS2E3YSs2Y0l1SEVaN1phK3poUGFRbHpBT1pseApmdUJtU2N1bTh1UVRyRUY1K1VtNXprd0M3RVhUZEgxY28vKy9WL2ZwT3R4SWc0WE80a2N1Z1plZlZtNUVSZlZTCk1BPT0KPWR0TU4KLS0tLS1FTkQgUEdQIFBVQkxJQyBLRVkgQkxPQ0stLS0tLQo='|base64 -d|apt-key add -"]
+{% endraw %}
+{%- if not cluster.saltstack_repo_key == 'none' %}
+{% set salt_repo_key = salt['hashutil.base64_b64encode'](cluster.saltstack_repo_key) %}
+  apt_00_set_gpg: ["curtin", "in-target", "--", "sh", "-c", "echo '{{salt_repo_key}}' | base64 -d | apt-key add -"]
+{%- endif %}
+  apt_01_set_repo: ["curtin", "in-target", "--", "sh", "-c", "echo 'deb [arch=amd64] {{ cluster.saltstack_repo_xenial }}' >> /etc/apt/sources.list"]
+{% raw %}
   apt_03_update: ["curtin", "in-target", "--", "apt-get", "update"]
   salt_01_install: ["curtin", "in-target", "--", "apt-get", "-y", "install", "salt-minion"]
 {% endraw %}
@@ -35,4 +40,4 @@
   driver_06_depmod: ["curtin", "in-target", "--", "depmod"]
   driver_07_update_initramfs: ["curtin", "in-target", "--", "update-initramfs", "-u"]
 {{endif}}
-{% endraw %}
+{% endraw %}
\ No newline at end of file
diff --git a/maas/machines/wait_for_deployed.sls b/maas/machines/wait_for_deployed.sls
new file mode 100644
index 0000000..ebeedac
--- /dev/null
+++ b/maas/machines/wait_for_deployed.sls
@@ -0,0 +1,13 @@
+{%- from "maas/map.jinja" import region with context %}
+
+maas_login_admin:
+  cmd.run:
+  - name: "maas-region apikey --username {{ region.admin.username }} > /var/lib/maas/.maas_credentials"
+
+wait_for_machines_deployed:
+  module.run:
+  - name: maas.wait_for_machine_status
+  - kwargs:
+        req_status: "Deployed"
+  - require:
+    - cmd: maas_login_admin
diff --git a/maas/machines/wait_for_ready.sls b/maas/machines/wait_for_ready.sls
new file mode 100644
index 0000000..c5d3c28
--- /dev/null
+++ b/maas/machines/wait_for_ready.sls
@@ -0,0 +1,11 @@
+{%- from "maas/map.jinja" import region with context %}
+
+maas_login_admin:
+  cmd.run:
+  - name: "maas-region apikey --username {{ region.admin.username }} > /var/lib/maas/.maas_credentials"
+
+wait_for_machines_ready:
+  module.run:
+  - name: maas.wait_for_machine_status
+  - require:
+    - cmd: maas_login_admin
diff --git a/metadata/service/cluster/single.yml b/metadata/service/cluster/single.yml
index 4c1fa5a..5c91bd1 100644
--- a/metadata/service/cluster/single.yml
+++ b/metadata/service/cluster/single.yml
@@ -8,4 +8,38 @@
       enabled: true
       region:
         port: 80
-        host: localhost
\ No newline at end of file
+        host: localhost
+      saltstack_repo_key: |
+        -----BEGIN PGP PUBLIC KEY BLOCK-----
+        Version: GnuPG v2
+
+        mQENBFOpvpgBCADkP656H41i8fpplEEB8IeLhugyC2rTEwwSclb8tQNYtUiGdna9
+        m38kb0OS2DDrEdtdQb2hWCnswxaAkUunb2qq18vd3dBvlnI+C4/xu5ksZZkRj+fW
+        tArNR18V+2jkwcG26m8AxIrT+m4M6/bgnSfHTBtT5adNfVcTHqiT1JtCbQcXmwVw
+        WbqS6v/LhcsBE//SHne4uBCK/GHxZHhQ5jz5h+3vWeV4gvxS3Xu6v1IlIpLDwUts
+        kT1DumfynYnnZmWTGc6SYyIFXTPJLtnoWDb9OBdWgZxXfHEcBsKGha+bXO+m2tHA
+        gNneN9i5f8oNxo5njrL8jkCckOpNpng18BKXABEBAAG0MlNhbHRTdGFjayBQYWNr
+        YWdpbmcgVGVhbSA8cGFja2FnaW5nQHNhbHRzdGFjay5jb20+iQE4BBMBAgAiBQJT
+        qb6YAhsDBgsJCAcDAgYVCAIJCgsEFgIDAQIeAQIXgAAKCRAOCKFJ3le/vhkqB/0Q
+        WzELZf4d87WApzolLG+zpsJKtt/ueXL1W1KA7JILhXB1uyvVORt8uA9FjmE083o1
+        yE66wCya7V8hjNn2lkLXboOUd1UTErlRg1GYbIt++VPscTxHxwpjDGxDB1/fiX2o
+        nK5SEpuj4IeIPJVE/uLNAwZyfX8DArLVJ5h8lknwiHlQLGlnOu9ulEAejwAKt9CU
+        4oYTszYM4xrbtjB/fR+mPnYh2fBoQO4d/NQiejIEyd9IEEMd/03AJQBuMux62tjA
+        /NwvQ9eqNgLw9NisFNHRWtP4jhAOsshv1WW+zPzu3ozoO+lLHixUIz7fqRk38q8Q
+        9oNR31KvrkSNrFbA3D89uQENBFOpvpgBCADJ79iH10AfAfpTBEQwa6vzUI3Eltqb
+        9aZ0xbZV8V/8pnuU7rqM7Z+nJgldibFk4gFG2bHCG1C5aEH/FmcOMvTKDhJSFQUx
+        uhgxttMArXm2c22OSy1hpsnVG68G32Nag/QFEJ++3hNnbyGZpHnPiYgej3FrerQJ
+        zv456wIsxRDMvJ1NZQB3twoCqwapC6FJE2hukSdWB5yCYpWlZJXBKzlYz/gwD/Fr
+        GL578WrLhKw3UvnJmlpqQaDKwmV2s7MsoZogC6wkHE92kGPG2GmoRD3ALjmCvN1E
+        PsIsQGnwpcXsRpYVCoW7e2nW4wUf7IkFZ94yOCmUq6WreWI4NggRcFC5ABEBAAGJ
+        AR8EGAECAAkFAlOpvpgCGwwACgkQDgihSd5Xv74/NggA08kEdBkiWWwJZUZEy7cK
+        WWcgjnRuOHd4rPeT+vQbOWGu6x4bxuVf9aTiYkf7ZjVF2lPn97EXOEGFWPZeZbH4
+        vdRFH9jMtP+rrLt6+3c9j0M8SIJYwBL1+CNpEC/BuHj/Ra/cmnG5ZNhYebm76h5f
+        T9iPW9fFww36FzFka4VPlvA4oB7ebBtquFg3sdQNU/MmTVV4jPFWXxh4oRDDR+8N
+        1bcPnbB11b5ary99F/mqr7RgQ+YFF0uKRE3SKa7a+6cIuHEZ7Za+zhPaQlzAOZlx
+        fuBmScum8uQTrEF5+Um5zkwC7EXTdH1co/+/V/fpOtxIg4XO4kcugZefVm5ERfVS
+        MA==
+        =dtMN
+        -----END PGP PUBLIC KEY BLOCK-----
+      saltstack_repo_trusty: "http://repo.saltstack.com/apt/ubuntu/16.04/amd64/2016.3/ trusty main"
+      saltstack_repo_xenial: "http://repo.saltstack.com/apt/ubuntu/16.04/amd64/2016.3/ xenial main"
\ No newline at end of file