Merge "Adding docker image list for 3.0.2"
diff --git a/ansible/library/rancher1_api.py b/ansible/library/rancher1_api.py
new file mode 100644
index 0000000..5d74da1
--- /dev/null
+++ b/ansible/library/rancher1_api.py
@@ -0,0 +1,598 @@
+#!/usr/bin/python
+
+from ansible.module_utils.basic import AnsibleModule
+
+import requests
+import json
+import functools
+import time
+
+DOCUMENTATION = """
+---
+module: rancher1_api
+short_description: Client library for rancher API
+description:
+  - This module modifies a rancher 1.6 using it's API (v1).
+  - It supports some rancher features by the virtue of a 'mode'.
+  - 'modes' hide from you some necessary cruft and expose you to the only
+    important and interestig variables wich must be set. The mode mechanism
+    makes this module more easy to use and you don't have to create an
+    unnecessary boilerplate for the API.
+  - Only a few modes are/will be implemented so far - as they are/will be
+    needed. In the future the 'raw' mode can be added to enable you to craft
+    your own API requests, but that would be on the same level of a user
+    experience as running curl commands, and because the rancher 1.6 is already
+    obsoleted by the project, it would be a wasted effort.
+options:
+  rancher:
+    description:
+      - The domain name or the IP address and the port of the rancher
+        where API is exposed.
+      - For example: http://10.0.0.1:8080
+    required: true
+    aliases:
+      - server
+      - rancher_server
+      - rancher_api
+      - api
+  account_key:
+    description:
+      - The public and secret part of the API key-pair separated by colon.
+      - You can find all your keys in web UI.
+      - For example:
+        B1716C4133D3825051CB:3P2eb3QhokFKYUiXRNZLxvGNSRYgh6LHjuMicCHQ
+    required: false
+  mode:
+    description:
+      - A recognized mode how to deal with some concrete configuration task
+        in rancher API to ease the usage.
+      - The implemented modes so far are:
+        'settings':
+            Many options under <api_server>/v1/settings API url and some can
+            be seen also under advanced options in the web UI.
+        'access_control':
+            It setups user and password for the account (defaults to 'admin')
+            and it enables the local authentication - so the web UI and API
+            will require username/password (UI) or apikey (API).
+    required: true
+    aliases:
+      - rancher_mode
+      - api_mode
+    choices:
+      - settings
+      - access_control
+  data:
+    description:
+      - Dictionary with key/value pairs. The actual names and meaning of pairs
+        depends on the used mode.
+      - settings mode:
+        option - Option/path in JSON API (url).
+        value - A new value to replace the current one.
+      - access_control mode:
+        account_id - The unique ID of the account - the default rancher admin
+        has '1a1'. Better way would be to just create arbitrary username and
+        set credentials for that, but due to time constraints, the route with
+        an ID is simpler. The designated '1a1' could be hardcoded and hidden
+        but if the user will want to use some other account (there are many),
+        then it can be just changed to some other ID.
+        password - A new password in a plaintext.
+    required: true
+  timeout:
+    description:
+      - How long in seconds to wait for a response before raising error
+    required: false
+    default: 10.0
+"""
+
+default_timeout = 10.0
+
+
+class ModeError(Exception):
+    pass
+
+
+def _decorate_rancher_api_request(request_method):
+
+    @functools.wraps(request_method)
+    def wrap_request(*args, **kwargs):
+
+        response = request_method(*args, **kwargs)
+        authorized = True
+
+        if response.status_code == 401:
+            authorized = False
+        elif response.status_code != requests.codes.ok:
+            response.raise_for_status()
+
+        try:
+            json_data = response.json()
+        except Exception:
+            json_data = None
+
+        return json_data, authorized
+
+    return wrap_request
+
+
+@_decorate_rancher_api_request
+def get_rancher_api_value(url, headers=None, timeout=default_timeout,
+                          username=None, password=None):
+
+    if username and password:
+        return requests.get(url, headers=headers,
+                            timeout=timeout,
+                            allow_redirects=False,
+                            auth=(username, password))
+    else:
+        return requests.get(url, headers=headers,
+                            timeout=timeout,
+                            allow_redirects=False)
+
+
+@_decorate_rancher_api_request
+def set_rancher_api_value(url, payload, headers=None, timeout=default_timeout,
+                          username=None, password=None, method='PUT'):
+
+    if method == 'PUT':
+        request_set_method = requests.put
+    elif method == 'POST':
+        request_set_method = requests.post
+    else:
+        raise ModeError('ERROR: Wrong request method: %s' % str(method))
+
+    if username and password:
+        return request_set_method(url, headers=headers,
+                                  timeout=timeout,
+                                  allow_redirects=False,
+                                  data=json.dumps(payload),
+                                  auth=(username, password))
+    else:
+        return request_set_method(url, headers=headers,
+                                  timeout=timeout,
+                                  allow_redirects=False,
+                                  data=json.dumps(payload))
+
+
+def create_rancher_api_url(server, mode, option):
+    request_url = server.strip('/') + '/v1/'
+
+    if mode == 'raw':
+        request_url += option.strip('/')
+    elif mode == 'settings':
+        request_url += 'settings/' + option.strip('/')
+    elif mode == 'access_control':
+        request_url += option.strip('/')
+
+    return request_url
+
+
+def get_keypair(keypair):
+    if keypair:
+        keypair = keypair.split(':')
+        if len(keypair) == 2:
+            return keypair[0], keypair[1]
+
+    return None, None
+
+
+def mode_access_control(api_url, data=None, headers=None,
+                        timeout=default_timeout, access_key=None,
+                        secret_key=None, dry_run=False):
+
+    # returns true if local auth was enabled or false if passwd changed
+    def is_admin_enabled(json_data, password):
+        try:
+            if json_data['type'] == "localAuthConfig" and \
+                    json_data['accessMode'] == "unrestricted" and \
+                    json_data['username'] == "admin" and \
+                    json_data['password'] == password and \
+                    json_data['enabled']:
+                return True
+        except Exception:
+            pass
+
+        try:
+            if json_data['type'] == "error" and \
+                    json_data['code'] == "IncorrectPassword":
+                return False
+        except Exception:
+            pass
+
+        # this should never happen
+        raise ModeError('ERROR: Unknown status of the local authentication')
+
+    def create_localauth_payload(password):
+        payload = {
+            "enabled": True,
+            "accessMode": "unrestricted",
+            "username": "admin",
+            "password": password
+        }
+
+        return payload
+
+    def get_admin_password_id():
+        # assemble request URL
+        request_url = api_url + 'accounts/' + data['account_id'].strip('/') \
+            + '/credentials'
+
+        # API get current value
+        try:
+            json_response, authorized = \
+                get_rancher_api_value(request_url,
+                                      username=access_key,
+                                      password=secret_key,
+                                      headers=headers,
+                                      timeout=timeout)
+        except requests.HTTPError as e:
+            raise ModeError(str(e))
+        except requests.Timeout as e:
+            raise ModeError(str(e))
+
+        if not authorized or not json_response:
+            raise ModeError('ERROR: BAD RESPONSE (GET) - no json value in '
+                            + 'the response')
+
+        try:
+            for item in json_response['data']:
+                if item['type'] == 'password' and \
+                        item['accountId'] == data['account_id']:
+                    return item['id']
+        except Exception:
+            pass
+
+        return None
+
+    def remove_password(password_id, action):
+        if action == 'deactivate':
+            action_status = 'deactivating'
+        elif action == 'remove':
+            action_status = 'removing'
+
+        request_url = api_url + 'passwords/' + password_id + \
+            '/?action=' + action
+
+        try:
+            json_response, authorized = \
+                set_rancher_api_value(request_url,
+                                      {},
+                                      username=access_key,
+                                      password=secret_key,
+                                      headers=headers,
+                                      method='POST',
+                                      timeout=timeout)
+        except requests.HTTPError as e:
+            raise ModeError(str(e))
+        except requests.Timeout as e:
+            raise ModeError(str(e))
+
+        if not authorized or not json_response:
+            raise ModeError('ERROR: BAD RESPONSE (POST) - no json value in '
+                            + 'the response')
+
+        if json_response['state'] != action_status:
+            raise ModeError("ERROR: Failed to '%s' the password: %s" %
+                            (action, password_id))
+
+    # check if data contains all required fields
+    try:
+        if not isinstance(data['account_id'], str) or data['account_id'] == '':
+            raise ModeError("ERROR: 'account_id' must contain an id of the "
+                            + "affected account")
+    except KeyError:
+        raise ModeError("ERROR: Mode 'access_control' requires the field: "
+                        + "'account_id': %s" % str(data))
+    try:
+        if not isinstance(data['password'], str) or data['password'] == '':
+            raise ModeError("ERROR: 'password' must contain some password")
+    except KeyError:
+        raise ModeError("ERROR: Mode 'access_control' requires the field: "
+                        + "'password': %s" % str(data))
+
+    # assemble request URL
+    request_url = api_url + 'localauthconfigs'
+
+    # API get current value
+    try:
+        json_response, authorized = \
+            get_rancher_api_value(request_url,
+                                  username=access_key,
+                                  password=secret_key,
+                                  headers=headers,
+                                  timeout=timeout)
+    except requests.HTTPError as e:
+        raise ModeError(str(e))
+    except requests.Timeout as e:
+        raise ModeError(str(e))
+
+    if not authorized or not json_response:
+        raise ModeError('ERROR: BAD RESPONSE (GET) - no json value in the '
+                        + 'response')
+
+    # we will check if local auth is enabled or not
+    enabled = False
+    try:
+        for item in json_response['data']:
+            if item['type'] == 'localAuthConfig' and \
+                    item['accessMode'] == 'unrestricted' and \
+                    item['enabled']:
+                enabled = True
+                break
+    except Exception:
+        enabled = False
+
+    if dry_run:
+        # we will not set anything and only signal potential change
+        if enabled:
+            changed = False
+        else:
+            changed = True
+    else:
+        # we will try to enable again with the same password
+        localauth_payload = create_localauth_payload(data['password'])
+        try:
+            json_response, authorized = \
+                set_rancher_api_value(request_url,
+                                      localauth_payload,
+                                      username=access_key,
+                                      password=secret_key,
+                                      headers=headers,
+                                      method='POST',
+                                      timeout=timeout)
+        except requests.HTTPError as e:
+            raise ModeError(str(e))
+        except requests.Timeout as e:
+            raise ModeError(str(e))
+
+        # here we ignore authorized status - we will try to reset password
+        if not json_response:
+            raise ModeError('ERROR: BAD RESPONSE (POST) - no json value in '
+                            + 'the response')
+
+        # we check if the admin was already set or not...
+        if enabled and is_admin_enabled(json_response, data['password']):
+            # it was enabled before and password is the same - no change
+            changed = False
+        elif is_admin_enabled(json_response, data['password']):
+            # we enabled it for the first time
+            changed = True
+        # ...and reset password if needed (unauthorized access)
+        else:
+            # local auth is enabled but the password differs
+            # we must reset the admin's password
+            password_id = get_admin_password_id()
+
+            if password_id is None:
+                raise ModeError("ERROR: admin's password is set, but we "
+                                + "cannot identify it")
+
+            # One of the way to reset the password is to remove it first
+            # TODO - refactor this
+            remove_password(password_id, 'deactivate')
+            time.sleep(2)
+            remove_password(password_id, 'remove')
+            time.sleep(1)
+
+            try:
+                json_response, authorized = \
+                    set_rancher_api_value(request_url,
+                                          localauth_payload,
+                                          username=access_key,
+                                          password=secret_key,
+                                          headers=headers,
+                                          method='POST',
+                                          timeout=timeout)
+            except requests.HTTPError as e:
+                raise ModeError(str(e))
+            except requests.Timeout as e:
+                raise ModeError(str(e))
+
+            # finally we signal the change
+            changed = True
+
+    if changed:
+        msg = "Local authentication is enabled, admin has assigned password"
+    else:
+        msg = "Local authentication was already enabled, admin's password " \
+            + "is unchanged"
+
+    return changed, msg
+
+
+def mode_settings(api_url, data=None, headers=None, timeout=default_timeout,
+                  access_key=None, secret_key=None, dry_run=False):
+
+    def is_valid_rancher_api_option(json_data):
+
+        try:
+            api_activeValue = json_data['activeValue']
+            api_source = json_data['source']
+        except Exception:
+            return False
+
+        if api_activeValue is None and api_source is None:
+            return False
+
+        return True
+
+    def create_rancher_api_payload(json_data, new_value):
+
+        payload = {}
+        differs = False
+
+        try:
+            api_id = json_data['id']
+            api_activeValue = json_data['activeValue']
+            api_name = json_data['name']
+            api_source = json_data['source']
+        except Exception:
+            raise ValueError
+
+        payload.update({"activeValue": api_activeValue,
+                        "id": api_id,
+                        "name": api_name,
+                        "source": api_source,
+                        "value": new_value})
+
+        if api_activeValue != new_value:
+            differs = True
+
+        return differs, payload
+
+    # check if data contains all required fields
+    try:
+        if not isinstance(data['option'], str) or data['option'] == '':
+            raise ModeError("ERROR: 'option' must contain a name of the "
+                            + "option")
+    except KeyError:
+        raise ModeError("ERROR: Mode 'settings' requires the field: 'option': "
+                        + "%s" % str(data))
+    try:
+        if not isinstance(data['value'], str) or data['value'] == '':
+            raise ModeError("ERROR: 'value' must contain a value")
+    except KeyError:
+        raise ModeError("ERROR: Mode 'settings' requires the field: 'value': "
+                        + "%s" % str(data))
+
+    # assemble request URL
+    request_url = api_url + 'settings/' + data['option'].strip('/')
+
+    # API get current value
+    try:
+        json_response, authorized = \
+            get_rancher_api_value(request_url,
+                                  username=access_key,
+                                  password=secret_key,
+                                  headers=headers,
+                                  timeout=timeout)
+    except requests.HTTPError as e:
+        raise ModeError(str(e))
+    except requests.Timeout as e:
+        raise ModeError(str(e))
+
+    if not authorized or not json_response:
+        raise ModeError('ERROR: BAD RESPONSE (GET) - no json value in the '
+                        + 'response')
+
+    if is_valid_rancher_api_option(json_response):
+        valid = True
+        try:
+            differs, payload = create_rancher_api_payload(json_response,
+                                                          data['value'])
+        except ValueError:
+            raise ModeError('ERROR: INVALID JSON - missing json values in '
+                            + 'the response')
+    else:
+        valid = False
+
+    if valid and differs and dry_run:
+        # ansible dry-run mode
+        changed = True
+    elif valid and differs:
+        # API set new value
+        try:
+            json_response, authorized = \
+                set_rancher_api_value(request_url,
+                                      payload,
+                                      username=access_key,
+                                      password=secret_key,
+                                      headers=headers,
+                                      timeout=timeout)
+        except requests.HTTPError as e:
+            raise ModeError(str(e))
+        except requests.Timeout as e:
+            raise ModeError(str(e))
+
+        if not authorized or not json_response:
+            raise ModeError('ERROR: BAD RESPONSE (PUT) - no json value in '
+                            + 'the response')
+        else:
+            changed = True
+    else:
+        changed = False
+
+    if changed:
+        msg = "Option '%s' is now set to the new value: %s" \
+            % (data['option'], data['value'])
+    else:
+        msg = "Option '%s' is unchanged." % (data['option'])
+
+    return changed, msg
+
+
+def mode_handler(server, rancher_mode, data=None, timeout=default_timeout,
+                 account_key=None, dry_run=False):
+
+    changed = False
+    msg = 'UNKNOWN: UNAPPLICABLE MODE'
+
+    # check API key-pair
+    if account_key:
+        access_key, secret_key = get_keypair(account_key)
+        if not (access_key and secret_key):
+            raise ModeError('ERROR: INVALID API KEY-PAIR')
+
+    # all requests share these headers
+    http_headers = {'Content-Type': 'application/json',
+                    'Accept': 'application/json'}
+
+    # assemble API url
+    api_url = server.strip('/') + '/v1/'
+
+    if rancher_mode == 'settings':
+        changed, msg = mode_settings(api_url, data=data,
+                                     headers=http_headers,
+                                     timeout=timeout,
+                                     access_key=access_key,
+                                     secret_key=secret_key,
+                                     dry_run=dry_run)
+    elif rancher_mode == 'access_control':
+        changed, msg = mode_access_control(api_url, data=data,
+                                           headers=http_headers,
+                                           timeout=timeout,
+                                           access_key=access_key,
+                                           secret_key=secret_key,
+                                           dry_run=dry_run)
+
+    return changed, msg
+
+
+def main():
+    module = AnsibleModule(
+        argument_spec=dict(
+            rancher=dict(type='str', required=True,
+                         aliases=['server',
+                                  'rancher_api',
+                                  'rancher_server',
+                                  'api']),
+            account_key=dict(type='str', required=False),
+            mode=dict(required=True,
+                      choices=['settings', 'access_control'],
+                      aliases=['api_mode']),
+            data=dict(type='dict', required=True),
+            timeout=dict(type='float', default=default_timeout),
+        ),
+        supports_check_mode=True
+    )
+
+    rancher_server = module.params['rancher']
+    rancher_account_key = module.params['account_key']
+    rancher_mode = module.params['mode']
+    rancher_data = module.params['data']
+    rancher_timeout = module.params['timeout']
+
+    try:
+        changed, msg = mode_handler(rancher_server,
+                                    rancher_mode,
+                                    data=rancher_data,
+                                    account_key=rancher_account_key,
+                                    timeout=rancher_timeout,
+                                    dry_run=module.check_mode)
+    except ModeError as e:
+        module.fail_json(msg=str(e))
+
+    module.exit_json(changed=changed, msg=msg)
+
+
+if __name__ == '__main__':
+    main()
diff --git a/ansible/roles/nfs/molecule/default/cleanup.yml b/ansible/roles/nfs/molecule/default/cleanup.yml
index a085bd5..af47ed8 100644
--- a/ansible/roles/nfs/molecule/default/cleanup.yml
+++ b/ansible/roles/nfs/molecule/default/cleanup.yml
@@ -1,6 +1,5 @@
 ---
 - name: Cleanup
-  hosts: all
-  ignore_unreachable: true
+  hosts: all:!nfs-server
   roles:
     - cleanup-nfs
diff --git a/ansible/roles/nfs/molecule/default/molecule.yml b/ansible/roles/nfs/molecule/default/molecule.yml
index f6610ec..7bacf3c 100644
--- a/ansible/roles/nfs/molecule/default/molecule.yml
+++ b/ansible/roles/nfs/molecule/default/molecule.yml
@@ -35,8 +35,6 @@
       - /sys/fs/cgroup:/sys/fs/cgroup:ro
 provisioner:
   name: ansible
-  playbooks:
-    cleanup: cleanup.yml
   env:
     ANSIBLE_ROLES_PATH: "../../../../test/roles"
   inventory:
diff --git a/ansible/roles/rancher/defaults/main.yml b/ansible/roles/rancher/defaults/main.yml
index 6ab52e6..6d354e6 100644
--- a/ansible/roles/rancher/defaults/main.yml
+++ b/ansible/roles/rancher/defaults/main.yml
@@ -4,3 +4,30 @@
 rancher_redeploy_k8s_env: true
 rancher_cluster_health_state: healthy
 rancher_cluster_health_check_retries: 30
+rancher:
+  # The following variables can be set via the UI under advanced/settings.
+  # All of these affect tables in the cattle db and are uninteresting
+  # to the user (they serve the internal logic of the cattle), but
+  # they can eat a lot of space when a deployment is busy or faulty.
+  #
+  # Audit-Log is the only user-facing option here and it is represented
+  # in the UI.
+  #
+  # Auto-purge deleted entries from most tables after this long (seconds)
+  main_tables_purge_after_seconds: 28800  # 8 hours
+  # Auto-purge Event entries after this long (seconds)
+  events_purge_after_seconds: 28800       # 8 hours
+  # Auto-purge Service Log entries after this long (seconds)
+  service_log_purge_after_seconds: 86400  # 1 day
+  # Auto-purge Audit Log entries after this long (seconds)
+  audit_log_purge_after_seconds: 2592000  # 30 days
+
+  # By default we don't enable local authentication (mainly due to
+  # to the fact that rancher_k8s_environment.py would have to be
+  # rewritten completely)
+  # But if you don't need to run rancher_kubernetes playbook more
+  # than once (you should not have to under the terms of a regular
+  # installation), then you can safely enable it.
+  auth_enabled: false
+  # Set this password for the rancher admin account:
+  admin_password: "admin"
diff --git a/ansible/roles/rancher/tasks/rancher_server.yml b/ansible/roles/rancher/tasks/rancher_server.yml
index e1eb5a5..4cda372 100644
--- a/ansible/roles/rancher/tasks/rancher_server.yml
+++ b/ansible/roles/rancher/tasks/rancher_server.yml
@@ -32,6 +32,14 @@
   delay: 5
   until: env.data is defined
 
+# There is a lack of idempotency in the previous task and so there are new api
+# key-pairs created with each run.
+#
+# ToDo: fix idempotency of rancher role
+#
+# Anyway as rke will be default k8s orchestrator in Dublin, it's supposed to be
+# low prio topic. The following tasks dealing with the API are ignoring this problem
+# and they simply use the new created API key-pair, which is set as a fact here:
 - name: Set apikey values
   set_fact:
     k8s_env_id: "{{ env.data.environment.id }}"
@@ -39,3 +47,49 @@
     key_private: "{{ env.data.apikey.private }}"
     rancher_agent_image: "{{ env.data.registration_tokens.image }}"
     rancher_agent_reg_url: "{{ env.data.registration_tokens.reg_url }}"
+
+# By default disabled - when enabled this playbook cannot be run more than once.
+- name: Setup rancher admin password and enable authentication
+  rancher1_api:
+    server: "{{ rancher_server_url }}"
+    account_key: "{{ key_public }}:{{ key_private }}"
+    mode: access_control
+    data:
+      account_id: 1a1 # default rancher admin account
+      password: "{{ rancher.admin_password }}"
+  when: "rancher.auth_enabled is defined and rancher.auth_enabled"
+
+- name: Configure the size of the rancher cattle db and logs
+  block:
+    - name: Main tables
+      rancher1_api:
+        server: "{{ rancher_server_url }}"
+        account_key: "{{ key_public }}:{{ key_private }}"
+        mode: settings
+        data:
+          option: main_tables.purge.after.seconds
+          value: "{{ rancher.main_tables_purge_after_seconds }}"
+    - name: Events
+      rancher1_api:
+        server: "{{ rancher_server_url }}"
+        account_key: "{{ key_public }}:{{ key_private }}"
+        mode: settings
+        data:
+          option: events.purge.after.seconds
+          value: "{{ rancher.events_purge_after_seconds }}"
+    - name: Service log
+      rancher1_api:
+        server: "{{ rancher_server_url }}"
+        account_key: "{{ key_public }}:{{ key_private }}"
+        mode: settings
+        data:
+          option: service_log.purge.after.seconds
+          value: "{{ rancher.service_log_purge_after_seconds }}"
+    - name: Audit log
+      rancher1_api:
+        server: "{{ rancher_server_url }}"
+        account_key: "{{ key_public }}:{{ key_private }}"
+        mode: settings
+        data:
+          option: audit_log.purge.after.seconds
+          value: "{{ rancher.audit_log_purge_after_seconds }}"
diff --git a/ansible/roles/resource-data/molecule/default/group_vars/all.yml b/ansible/roles/resource-data/molecule/default/group_vars/all.yml
index 558eacb..46ab3e0 100644
--- a/ansible/roles/resource-data/molecule/default/group_vars/all.yml
+++ b/ansible/roles/resource-data/molecule/default/group_vars/all.yml
@@ -1,5 +1,5 @@
 ---
-app_data_path: /opt/myleculeapp
+app_data_path: /opt/moleculeapp
 aux_data_path: "{{ app_data_path }}/runtime_images_source_dir"
 resources_dir: /data
 resources_filename: resources_package.tar
diff --git a/ansible/test/images/docker/centos7/Dockerfile b/ansible/test/images/docker/centos7/Dockerfile
index 67e3fb9..0f6e559 100644
--- a/ansible/test/images/docker/centos7/Dockerfile
+++ b/ansible/test/images/docker/centos7/Dockerfile
@@ -3,7 +3,7 @@
 RUN yum -y update && yum clean all
 
 RUN yum -y install openssh-server sudo openssh-clients \
-    epel-release python-docker-py iproute e2fsprogs
+    epel-release python-docker-py iproute e2fsprogs file
 RUN systemctl enable sshd.service
 
 VOLUME ["/run"]
diff --git a/ansible/test/molecule-docker/Dockerfile b/ansible/test/molecule-docker/Dockerfile
index e4207f2..6181731 100644
--- a/ansible/test/molecule-docker/Dockerfile
+++ b/ansible/test/molecule-docker/Dockerfile
@@ -3,6 +3,7 @@
 ARG USER_ID
 ARG GROUP_ID
 ARG DOCKER_GROUP_ID
+ARG DOCKER_USER
 
 # When user/group provided, create user to have matching ids (for the host user)
 # to avoid this docker writing files as root owned
@@ -10,11 +11,12 @@
     # shadow needed for addgroup
     # sshpass needed for accessing docker_host (localhost) with ssh and without password prompt
     apk --no-cache add shadow sshpass && \
-    addgroup -g ${GROUP_ID} molecule && \
-    adduser -D -u ${USER_ID} -G molecule molecule && \
+    addgroup -g ${GROUP_ID} ${DOCKER_USER} && \
+    adduser -D -u ${USER_ID} -G ${DOCKER_USER} ${DOCKER_USER} && \
     # Add user to same docker group as in docker_host to be able to use docker driver as sudo
     groupadd docker-host -g ${DOCKER_GROUP_ID} && \
-    usermod -aG ${DOCKER_GROUP_ID} molecule \
+    usermod -aG ${DOCKER_GROUP_ID} ${DOCKER_USER} \
 ;fi
 
-USER molecule
+USER ${DOCKER_USER}
+
diff --git a/ansible/test/molecule-docker/build.sh b/ansible/test/molecule-docker/build.sh
index 0b65f2a..b613e46 100755
--- a/ansible/test/molecule-docker/build.sh
+++ b/ansible/test/molecule-docker/build.sh
@@ -20,6 +20,7 @@
 
 SCRIPT_DIR=$(dirname "${0}")
 LOCAL_PATH=$(readlink -f "$SCRIPT_DIR")
+if [ $(id -u ${USER}) -eq "0" ]; then DOCKER_USER="root"; else DOCKER_USER="molecule"; fi
 
 set -e
 
@@ -27,6 +28,7 @@
     --build-arg USER_ID=$(id -u ${USER}) \
     --build-arg GROUP_ID=$(id -g ${USER}) \
     --build-arg DOCKER_GROUP_ID=$(getent group docker | cut -f 3 -d ':') \
+    --build-arg DOCKER_USER=${DOCKER_USER} \
     -t molecule-dev:2.20.0 \
     ${LOCAL_PATH}
 
diff --git a/ansible/test/roles/prepare-resource-data/tasks/prepare-infra-server.yml b/ansible/test/roles/prepare-resource-data/tasks/prepare-infra-server.yml
index b55842a..dfaca80 100644
--- a/ansible/test/roles/prepare-resource-data/tasks/prepare-infra-server.yml
+++ b/ansible/test/roles/prepare-resource-data/tasks/prepare-infra-server.yml
@@ -12,5 +12,4 @@
     name: nfs-utils
     state: present
   when:
-    - resources_on_nfs is defined
     - resources_on_nfs
diff --git a/ansible/test/roles/prepare-resource-data/tasks/prepare-resource-server.yml b/ansible/test/roles/prepare-resource-data/tasks/prepare-resource-server.yml
index 4057ba1..1f12555 100644
--- a/ansible/test/roles/prepare-resource-data/tasks/prepare-resource-server.yml
+++ b/ansible/test/roles/prepare-resource-data/tasks/prepare-resource-server.yml
@@ -1,9 +1,4 @@
 ---
-- name: Install file exacutable if not there for archive compression checking
-  package:
-    name: file
-    state: present
-
 - name: "Create resource dir {{ resources_dir }}"
   file:
     path: "{{ resources_dir }}/{{ subdir }}"
@@ -68,5 +63,4 @@
     - name: Export nfs
       command: exportfs -ar
   when:
-    - resources_on_nfs is defined
     - resources_on_nfs
diff --git a/build/data_lists/onap_3.0.x-npm.list b/build/data_lists/onap_3.0.x-npm.list
index 14c6861..a22b237 100644
--- a/build/data_lists/onap_3.0.x-npm.list
+++ b/build/data_lists/onap_3.0.x-npm.list
@@ -1,787 +1,389 @@
-abbrev@1.0.9
-abbrev@1.1.1
-abs@1.3.12
-accepts@1.1.4
-accepts@1.2.13
-accepts@1.3.5
-active-x-obfuscator@0.0.1
-addressparser@0.3.2
-adm-zip@0.4.7
-amdefine@1.0.1
-ansi-color@0.2.1
-ansi-regex@2.1.1
-ansi-styles@2.2.1
-anymatch@1.3.2
-any-promise@1.3.0
-append-field@0.1.0
-append-field@1.0.0
-argparse@0.1.16
-argparse@1.0.10
-array-find-index@1.0.2
-array-flatten@1.1.1
-array-unique@0.2.1
-array-unique@0.3.2
-arr-diff@2.0.0
-arr-diff@4.0.0
-arr-flatten@1.1.0
-arr-union@3.1.0
-asn1@0.1.11
-asn1@0.2.4
-assert-plus@0.1.5
-assert-plus@0.2.0
-assert-plus@1.0.0
-assign-symbols@1.0.0
 async@0.1.22
-async@0.2.10
-async@0.9.2
-async@1.5.2
-async@2.6.1
-async-each@1.0.1
-asynckit@0.4.0
-atob@2.1.2
-aws4@1.8.0
-aws-sign2@0.5.0
-aws-sign2@0.6.0
-balanced-match@1.0.0
-base@0.11.2
-base64id@0.1.0
-base64-url@1.2.1
-basic-auth@1.0.0
-basic-auth@1.0.4
-basic-auth-connect@1.0.0
-batch@0.5.1
-batch@0.5.3
-bcrypt-pbkdf@1.0.2
-bignumber.js@2.0.7
-bignumber.js@4.1.0
-binary-extensions@1.12.0
 bl@0.9.5
-body-parser@1.13.3
-body-parser@1.18.2
-body-parser@1.18.3
-body-parser@1.8.4
-boom@0.4.2
-boom@2.10.1
-bootstrap@3.4.0
-bootstrap-submenu@2.0.4
-bootstrap-table@1.13.1
 brace-expansion@1.1.11
-braces@1.8.5
-braces@2.3.2
-buffer-from@1.1.1
-buildmail@1.3.0
-builtin-modules@1.1.1
-busboy@0.2.14
-bytes@1.0.0
-bytes@2.1.0
-bytes@2.4.0
-bytes@3.0.0
-cache-base@1.0.1
-camelcase@2.1.1
-camelcase-keys@2.1.0
-capture-stack-trace@1.0.1
-caseless@0.11.0
-caseless@0.6.0
-chalk@1.1.3
-cheerio@0.17.0
-chokidar@1.7.0
-class-utils@0.3.6
-cli@0.6.6
-clone@0.1.18
-coffee-script@1.3.3
-coffee-script@1.8.0
-collection-visit@1.0.0
-colors@0.6.2
-colors@1.3.2
-combined-stream@0.0.7
-combined-stream@1.0.7
-commander@0.6.1
-commander@1.3.2
-commander@2.0.0
 commander@2.1.0
-commander@2.17.1
-commander@2.19.0
-component-emitter@1.1.2
-component-emitter@1.2.1
-compressible@2.0.15
 compression@1.1.2
-compression@1.5.2
-concat-map@0.0.1
-concat-stream@1.5.0
-concat-stream@1.6.2
 connect@2.26.1
-connect@2.30.2
-connect-timeout@1.3.0
-connect-timeout@1.6.2
-console-browserify@1.1.0
-content-disposition@0.5.2
-content-type@1.0.4
-cookie@0.1.2
-cookie@0.1.3
-cookie@0.3.1
 cookiejar@1.3.2
-cookie-parser@1.3.5
-cookie-signature@1.0.5
-cookie-signature@1.0.6
-copy-descriptor@0.1.1
-core-util-is@1.0.2
-cors@2.4.2
-crc@3.0.0
-crc@3.2.1
-crc@3.3.0
-crc@3.4.4
-create-error-class@3.0.2
-cron@1.0.4
-cryptiles@0.2.2
-cryptiles@2.0.5
-csrf@2.0.7
-csrf@3.0.6
-CSSselect@0.4.1
-CSSwhat@0.4.7
 csurf@1.6.6
-csurf@1.8.3
-csv@0.4.6
-csv-generate@0.0.6
-csv-parse@1.3.3
-csv-stringify@0.0.8
-csvtojson@0.5.14
-ctype@0.5.3
-currently-unhandled@0.4.1
-dashdash@1.14.1
-dateformat@1.0.12
-dateformat@1.0.2-1.2.3
-date-now@0.1.4
 debug@0.7.4
-debug@2.0.0
-debug@2.2.0
-debug@2.6.9
-decamelize@1.2.0
-decode-uri-component@0.2.0
-deep-equal@1.0.1
-deep-extend@0.6.0
-deep-is@0.1.3
-deffy@2.2.2
-define-property@0.2.5
-define-property@1.0.0
-define-property@2.0.2
-delayed-stream@0.0.5
-delayed-stream@1.0.0
 depd@0.4.5
-depd@1.0.1
-depd@1.1.1
-depd@1.1.2
-destroy@1.0.3
-destroy@1.0.4
-di@0.0.1
-dicer@0.2.5
-diff@1.0.7
-dns-sync@0.1.3
 domelementtype@1.1.3
-domelementtype@1.3.1
-domhandler@2.2.1
-domhandler@2.3.0
-dom-serializer@0.0.1
 domutils@1.4.3
-domutils@1.5.1
-duplexer@0.1.1
-duplexer2@0.0.2
-duplexer2@0.1.4
-ecc-jsbn@0.1.2
-ee-first@1.0.5
-ee-first@1.1.1
-ejs@0.8.8
-encodeurl@1.0.2
-entities@1.0.0
-entities@1.1.2
-err@1.1.1
-error-ex@1.3.2
 errorhandler@1.2.4
-errorhandler@1.4.3
-es6-promise@4.0.5
-escape-html@1.0.1
-escape-html@1.0.2
-escape-html@1.0.3
-escape-string-regexp@1.0.5
-escodegen@1.7.1
-esprima@1.0.4
-esprima@1.2.5
-esprima@2.5.0
-esprima@4.0.1
-estraverse@1.8.0
-estraverse@1.9.3
-esutils@2.0.2
-etag@1.3.1
-etag@1.4.0
-etag@1.5.1
-etag@1.7.0
-etag@1.8.1
-eventemitter2@0.4.14
-exec-limiter@3.2.11
-exit@0.1.2
-expand-brackets@0.1.5
-expand-brackets@2.1.4
-expand-range@1.8.2
 express@3.17.2
-express@4.16.3
-express@4.9.8
-express-session@1.11.3
-express-session@1.15.6
-express-session@1.8.2
 extend@1.2.1
-extend@3.0.2
-extend-shallow@2.0.1
-extend-shallow@3.0.2
-extglob@0.3.2
-extglob@2.0.4
-extract-zip@1.5.0
-extsprintf@1.3.0
-fast-levenshtein@1.0.7
-fd-slicer@1.0.1
-filename-regex@2.0.1
-fileset@0.1.8
-fileset@0.2.1
-fill-range@2.2.4
-fill-range@4.0.0
-finalhandler@0.2.0
-finalhandler@0.4.0
-finalhandler@1.1.1
-find-up@1.1.2
-findup-sync@0.1.3
-follow-redirects@0.0.3
-foreachasync@3.0.0
-forever-agent@0.5.2
-forever-agent@0.6.1
-for-in@1.0.2
-formatio@1.0.2
-form-data@0.1.2
-form-data@0.1.4
-form-data@2.1.4
 formidable@1.0.14
-for-own@0.1.5
-forwarded@0.1.2
-fragment-cache@0.2.1
 fresh@0.2.4
-fresh@0.3.0
-fresh@0.5.2
-fs-extra@0.11.1
-fs-extra@0.6.4
-fs-extra@1.0.0
 fs.extra@1.3.2
-fs.realpath@1.0.0
-function.name@1.0.11
-generate-function@2.3.1
-generate-object-property@1.2.0
-getobject@0.1.0
-getpass@0.1.7
-get-stdin@4.0.1
-get-value@2.0.6
-git-package-json@1.4.8
-git-source@1.1.8
-git-up@1.2.1
-git-url-parse@5.0.1
-glob@3.1.21
-glob@3.2.11
-glob@3.2.3
-glob@5.0.15
-glob@7.1.3
-glob-base@0.3.0
-glob-parent@2.0.0
-got@5.7.1
-graceful-fs@1.2.3
 graceful-fs@2.0.3
-graceful-fs@3.0.11
-graceful-fs@4.1.11
-graceful-fs@4.1.15
-growl@1.8.1
-grunt@0.4.5
 grunt-cli@0.1.13
-grunt-contrib-jshint@0.10.0
-grunt-legacy-log@0.1.3
-grunt-legacy-log-utils@0.1.1
 grunt-legacy-util@0.2.0
-grunt-simple-mocha@0.4.0
-gry@5.0.7
-handlebars@4.0.12
-har-validator@2.0.6
-has-ansi@2.0.0
-has-flag@1.0.0
-hasha@2.2.0
-has-value@0.3.1
-has-value@1.0.0
-has-values@0.1.4
-has-values@1.0.0
-hawk@1.1.1
-hawk@3.1.3
-hoek@0.9.1
-hoek@2.16.3
-hooker@0.2.3
-hosted-git-info@2.7.1
 htmlparser2@3.7.3
-htmlparser2@3.8.3
-http-errors@1.2.8
-http-errors@1.3.1
-http-errors@1.6.2
-http-errors@1.6.3
-http-proxy@0.10.4
-http-signature@0.10.1
-http-signature@1.1.1
-hyperquest@0.3.0
-hyperquest@1.3.0
-i@0.3.6
-ibrik@2.0.0
-iconv-lite@0.2.11
-iconv-lite@0.4.11
-iconv-lite@0.4.13
-iconv-lite@0.4.19
-iconv-lite@0.4.23
-iconv-lite@0.4.24
-iconv-lite@0.4.4
-imap@0.8.13
-indent-string@2.1.0
 inflight@1.0.6
-inherits@1.0.2
-inherits@2.0.3
-ini@1.3.5
-ipaddr.js@0.1.2
-ipaddr.js@1.0.5
-ipaddr.js@1.8.0
-irc@0.3.7
-is-accessor-descriptor@0.1.6
-is-accessor-descriptor@1.0.0
 isarray@0.0.1
-isarray@1.0.0
-is-arrayish@0.2.1
-is-binary-path@1.0.1
-is-buffer@1.1.6
-is-builtin-module@1.0.0
-is-data-descriptor@0.1.4
-is-data-descriptor@1.0.0
-is-descriptor@0.1.6
-is-descriptor@1.0.2
-is-dotfile@1.0.3
-is-equal-shallow@0.1.3
-isexe@2.0.0
-is-extendable@0.1.1
-is-extendable@1.0.1
-is-extglob@1.0.0
-is-finite@1.0.2
-is-glob@2.0.1
-is-my-ip-valid@1.0.0
-is-my-json-valid@2.19.0
-is-number@2.1.0
-is-number@3.0.0
-is-number@4.0.0
-isobject@2.1.0
-isobject@3.0.1
-is-plain-object@2.0.4
-is-posix-bracket@0.1.1
-is-primitive@2.0.0
-is-property@1.0.2
-is-redirect@1.0.0
-is-retry-allowed@1.1.0
-is-ssh@1.3.0
-isstream@0.1.2
-is-stream@1.1.0
-istanbul@0.3.22
-is-typedarray@1.0.0
-is-utf8@0.2.1
-is-windows@1.0.2
-iterate-object@1.3.2
-jade@0.26.3
-jsbn@0.1.1
-jshint@2.5.11
-jsonfile@1.0.1
-jsonfile@2.4.0
-jsonpointer@4.0.1
-json-schema@0.2.3
-json-stringify-safe@5.0.1
-jsprim@1.4.1
 js-yaml@2.0.5
-js-yaml@3.12.0
-karma@0.12.37
-karma-chrome-launcher@0.1.12
-karma-coverage@0.2.7
-karma-firefox-launcher@0.1.7
-karma-jasmine@0.2.3
-karma-phantomjs-launcher@1.0.4
-karma-spec-reporter@0.0.23
-kew@0.7.0
-keypress@0.1.0
-kind-of@3.2.2
-kind-of@4.0.0
-kind-of@5.1.0
-kind-of@6.0.2
-klaw@1.3.1
-levn@0.2.5
-libbase64@0.1.0
 libmime@0.1.7
-libmime@1.2.0
-libqp@0.1.1
-libqp@1.1.0
-limit-it@3.2.8
 load-json-file@1.1.0
-lodash@0.9.2
-lodash@1.3.1
-lodash@2.4.2
-lodash@3.10.1
-lodash@3.7.0
 lodash@4.17.11
-log4js@0.6.38
-loud-rejection@1.6.0
-lowercase-keys@1.0.1
-lru-cache@2.7.3
-lru-cache@4.1.3
-map-cache@0.2.2
-map-obj@1.0.1
-map-visit@1.0.0
-math-random@1.0.1
-media-typer@0.3.0
-meow@3.7.0
-merge-descriptors@0.0.2
-merge-descriptors@1.0.1
-method-override@2.2.0
-method-override@2.3.10
-methods@0.0.1
-methods@1.0.0
-methods@1.1.0
-methods@1.1.2
-micromatch@2.3.11
-micromatch@3.1.10
-mime@1.2.11
-mime@1.2.5
-mime@1.3.4
-mime@1.4.1
-mime@1.6.0
-mime-db@1.12.0
-mime-db@1.36.0
-mime-db@1.37.0
-mime-types@1.0.2
 mime-types@2.0.14
-mime-types@2.1.20
-mime-types@2.1.21
-minimatch@0.2.14
-minimatch@0.3.0
-minimatch@0.4.0
-minimatch@1.0.0
-minimatch@2.0.10
-minimatch@3.0.4
-minimist@0.0.8
-minimist@1.2.0
-mixin-deep@1.3.1
-mkdirp@0.3.0
-mkdirp@0.3.5
-mkdirp@0.5.0
-mkdirp@0.5.1
-mocha@1.21.4
-moment@2.23.0
 morgan@1.3.2
-morgan@1.6.1
-mqtt@0.3.13
-ms@0.6.2
-ms@0.7.1
-ms@0.7.2
-ms@2.0.0
-multer@1.1.0
-multer@1.4.1
-multiparty@3.3.2
-mustache@0.8.2
-mysql@2.16.0
-mysql@2.7.0
-mz@1.3.0
-nan@1.0.0
-nanomatch@1.2.13
-native-or-bluebird@1.1.2
-natives@1.1.6
-ncp@0.4.2
 ncp@0.6.0
-needle@0.9.2
-negotiator@0.4.9
-negotiator@0.5.3
-negotiator@0.6.1
-nodemailer@1.3.0
-nodemailer-direct-transport@1.1.0
-nodemailer-smtp-transport@0.1.13
-nodemailer-wellknown@0.1.10
-node-status-codes@1.0.0
-node-uuid@1.4.8
-noop6@1.0.7
-nopt@1.0.10
-nopt@3.0.1
-nopt@3.0.6
-normalize-package-data@2.4.0
-normalize-path@2.1.1
-number-is-nan@1.0.1
-oargv@3.4.8
-oauth@0.9.12
-oauth-sign@0.4.0
-oauth-sign@0.8.2
-obj-def@1.0.6
 object-assign@3.0.0
-object-assign@4.1.1
-object-copy@0.1.0
-object.omit@2.0.1
-object.pick@1.3.0
-object-visit@1.0.1
-once@1.4.0
-one-by-one@3.2.6
-on-finished@2.1.0
-on-finished@2.3.0
-on-headers@1.0.1
-optimist@0.3.7
-optimist@0.6.1
-optionator@0.5.0
-options@0.0.6
-os-tmpdir@1.0.2
-package.json@2.0.1
-package-json@2.4.0
-package-json-path@1.0.7
-parse-glob@3.0.4
-parse-json@2.2.0
-parse-url@1.3.11
-parseurl@1.3.2
-pascalcase@0.1.1
-path@0.12.7
-path-exists@2.1.0
-path-is-absolute@1.0.1
-path-to-regexp@0.1.3
-path-to-regexp@0.1.7
-path-type@1.1.0
 pause@0.0.1
-pause@0.1.0
-pend@1.2.0
-phantomjs-prebuilt@2.1.14
-pify@2.3.0
-pinkie@2.0.4
-pinkie-promise@2.0.1
-pkginfo@0.3.1
-policyfile@0.0.4
-posix-character-classes@0.1.1
-prelude-ls@1.1.2
-prepend-http@1.0.4
-preserve@0.2.0
-pretty-data@0.40.0
-process@0.11.10
-process-nextick-args@1.0.7
-process-nextick-args@2.0.0
-progress@1.1.8
-properties-reader@0.0.9
-protocols@1.4.6
-proxy-addr@1.0.1
 proxy-addr@1.0.10
-proxy-addr@2.0.4
-pseudomap@1.0.2
-psl@1.1.31
-punycode@1.4.1
 punycode@2.1.1
-q@1.5.1
-qs@0.6.6
-qs@1.2.2
-qs@2.2.3
-qs@2.2.4
-qs@4.0.0
-qs@6.3.2
-qs@6.5.1
-qs@6.5.2
-randomatic@3.1.0
-random-bytes@1.0.0
 range-parser@1.0.3
-range-parser@1.2.0
-raw-body@1.3.0
-raw-body@2.1.7
-raw-body@2.3.2
-raw-body@2.3.3
-rc@1.2.8
-readable-stream@1.0.27-1
-readable-stream@1.0.34
-readable-stream@1.1.14
-readable-stream@2.0.6
-readable-stream@2.3.6
-read-all-stream@3.1.0
-readdirp@2.2.1
-read-pkg@1.1.0
-read-pkg-up@1.0.1
 redent@1.0.0
-redis@0.7.3
-reduce-component@1.0.1
-regex-cache@0.4.4
-regex-not@1.0.2
-registry-auth-token@3.3.2
-registry.npmjs.org@1.0.1
-registry-url@3.1.0
-remove-trailing-separator@1.1.0
-repeat-element@1.1.3
-repeating@2.0.1
-repeat-string@1.6.1
 request@2.42.0
-request@2.79.0
-request-progress@2.0.1
-require-all@1.0.0
-resolve@0.3.1
-resolve@1.1.7
-resolve-url@0.2.1
-response-time@2.0.1
-response-time@2.3.2
-ret@0.1.15
-rimraf@2.2.8
-rimraf@2.6.2
-rimraf@2.6.3
-r-json@1.2.8
-rndm@1.1.1
-rndm@1.2.0
-r-package-json@1.0.7
-safe-buffer@5.1.1
-safe-buffer@5.1.2
-safer-buffer@2.1.2
-safe-regex@1.1.0
-samsam@1.1.3
-sax@0.6.1
-scmp@1.0.0
-semver@4.3.6
-semver@5.6.0
-send@0.13.2
-send@0.16.2
-send@0.9.2
 send@0.9.3
-sentiment@0.2.3
-serve-favicon@2.1.7
-serve-favicon@2.3.2
-serve-index@1.2.1
-serve-index@1.7.3
-serve-static@1.10.3
-serve-static@1.13.2
-serve-static@1.6.5
-setprototypeof@1.0.3
-setprototypeof@1.1.0
-set-value@0.4.3
-set-value@2.0.0
-shelljs@0.3.0
-shelljs@0.5.3
-should@4.0.4
 sigmund@1.0.1
-signal-exit@3.0.2
-sinon@1.10.3
-sliced@1.0.1
 smtp-connection@1.3.8
-snapdragon@0.8.2
-snapdragon-node@2.1.1
-snapdragon-util@3.0.1
 sntp@0.2.4
-sntp@1.0.9
-socket.io@0.9.16
-socket.io-client@0.9.16
-source-map@0.1.34
-source-map@0.2.0
-source-map@0.4.4
-source-map@0.5.7
-source-map@0.6.1
-source-map-resolve@0.5.2
-source-map-url@0.4.0
-spdx-correct@3.0.2
-spdx-correct@3.1.0
-spdx-exceptions@2.2.0
-spdx-expression-parse@3.0.0
-spdx-license-ids@3.0.1
-spdx-license-ids@3.0.3
-split-string@3.1.0
-sprintf-js@1.0.3
-sqlstring@2.3.1
-sshpk@1.15.1
-static-extend@0.1.2
-statuses@1.2.1
-statuses@1.4.0
 statuses@1.5.0
-stream-counter@0.2.0
-streamsearch@0.1.2
-stream-transform@0.1.2
-string_decoder@0.10.31
-string_decoder@1.1.1
-stringstream@0.0.6
-strip-ansi@3.0.1
-strip-bom@2.0.0
 strip-indent@1.0.1
-strip-json-comments@1.0.4
-strip-json-comments@2.0.1
-superagent@0.18.0
-supertest@0.13.0
-supports-color@2.0.0
-supports-color@3.2.3
-swagger-ui-dist@3.19.3
-swagger-ui-express@4.0.1
 thenify@3.3.0
-thenify-all@1.6.0
-throttleit@1.0.0
-through2@0.6.5
 through@2.2.7
-timed-out@3.1.3
-tinycolor@0.0.1
-tmp@0.0.28
-to-object-path@0.3.0
-to-regex@3.0.2
-to-regex-range@2.1.1
-tough-cookie@2.3.4
 tough-cookie@2.5.0
-trim-newlines@1.0.0
-tsscmp@1.0.5
-tunnel-agent@0.4.3
-tweetnacl@0.14.5
-twitter-ng@0.6.2
-type-check@0.3.2
-typedarray@0.0.6
-type-is@1.5.7
-type-is@1.6.16
-typpy@2.3.10
-uglify-js@1.2.5
-uglify-js@2.4.15
-uglify-js@3.4.9
 uglify-to-browserify@1.0.2
-uid-safe@1.0.1
-uid-safe@1.1.0
-uid-safe@2.0.0
-uid-safe@2.1.4
-uid-safe@2.1.5
-ul@5.2.13
-underscore@1.6.0
-underscore@1.7.0
-underscore@1.9.1
-underscore.string@2.2.1
 underscore.string@2.3.3
-underscore.string@2.4.0
-union-value@1.0.0
-unpipe@1.0.0
-unset-value@1.0.0
-unzip-response@1.0.2
-urix@0.1.0
-url-parse-lax@1.0.0
-use@3.1.1
-useragent@2.3.0
-utf7@1.0.0
-util@0.10.4
-util@0.11.1
-util-deprecate@1.0.2
-utile@0.2.1
-utils-merge@1.0.0
-utils-merge@1.0.1
-uuid@3.3.2
 validate-npm-package-license@3.0.4
-vary@1.0.1
-vary@1.1.2
-verror@1.10.0
-vhost@3.0.2
-walk@2.3.14
-when@3.4.6
-which@1.0.9
-which@1.2.14
 wordwrap@0.0.3
-wordwrap@1.0.0
-wrappy@1.0.2
-ws@0.4.32
-xml2js@0.4.19
+ansi-color@0.2.1
+any-promise@1.3.0
+array-find-index@1.0.2
+balanced-match@1.0.0
+basic-auth@1.0.0
+builtin-modules@1.1.1
+coffee-script@1.3.3
+combined-stream@0.0.7
+core-util-is@1.0.2
+crc@3.4.4
+csrf@2.0.7
+csv-stringify@0.0.8
+entities@1.0.0
+etag@1.4.0
+exit@0.1.2
+finalhandler@0.2.0
+follow-redirects@0.0.3
+hoek@0.9.1
+ipaddr.js@1.0.5
+is-builtin-module@1.0.0
+is-utf8@0.2.1
+method-override@2.2.0
+minimatch@3.0.4
+mkdirp@0.3.5
+ms@2.0.0
+needle@0.9.2
+nodemailer-direct-transport@1.1.0
+node-uuid@1.4.8
+normalize-package-data@2.4.0
+oauth@0.9.12
+on-finished@2.3.0
+options@0.0.6
+parseurl@1.3.2
+path-is-absolute@1.0.1
+pinkie@2.0.4
+pretty-data@0.40.0
+rimraf@2.2.8
+sentiment@0.2.3
+stream-counter@0.2.0
+string_decoder@1.1.1
+trim-newlines@1.0.0
+twitter-ng@0.6.2
+type-is@1.6.16
+underscore.string@2.4.0
+walk@2.3.14
 xml2js@0.4.4
-xmlbuilder@10.1.1
+abbrev@1.1.1
+assert-plus@0.1.5
+async@0.2.10
+bootstrap@3.4.0
+cookie-parser@1.3.5
+debug@2.0.0
+dicer@0.2.5
+domelementtype@1.3.1
+domutils@1.5.1
+ee-first@1.0.5
+etag@1.5.1
+formatio@1.0.2
+fs.realpath@1.0.0
+getobject@0.1.0
+glob@3.1.21
+grunt-contrib-jshint@0.10.0
+grunt-simple-mocha@0.4.0
+htmlparser2@3.8.3
+http-signature@0.10.1
+iconv-lite@0.4.24
+inherits@1.0.2
+isarray@1.0.0
+libmime@1.2.0
+lodash@0.9.2
+media-typer@0.3.0
+mime-db@1.12.0
+mime-types@2.1.21
+minimist@0.0.8
+mkdirp@0.5.0
+multer@1.1.0
+native-or-bluebird@1.1.2
+object-assign@4.1.1
+on-headers@1.0.1
+properties-reader@0.0.9
+readable-stream@1.0.27-1
+signal-exit@3.0.2
+spdx-license-ids@3.0.3
+stringstream@0.0.6
+strip-json-comments@1.0.4
+thenify-all@1.6.0
+uid-safe@1.0.1
+underscore@1.6.0
+utf7@1.0.0
+vary@1.0.1
+addressparser@0.3.2
+append-field@0.1.0
+async@0.9.2
+bignumber.js@2.0.7
+busboy@0.2.14
+component-emitter@1.1.2
+concat-map@0.0.1
+connect-timeout@1.3.0
+cors@2.4.2
+csv@0.4.6
+csvtojson@0.5.14
+dateformat@1.0.12
+domhandler@2.2.1
+duplexer@0.1.1
+entities@1.1.2
+express@4.9.8
+foreachasync@3.0.0
+graceful-fs@4.1.15
+http-errors@1.2.8
+iconv-lite@0.4.4
+irc@0.3.7
+is-arrayish@0.2.1
+jshint@2.5.11
+keypress@0.1.0
+libqp@0.1.1
+loud-rejection@1.6.0
+minimatch@0.2.14
+mkdirp@0.5.1
+mqtt@0.3.13
+mysql@2.7.0
+negotiator@0.4.9
+nodemailer-smtp-transport@0.1.13
+oauth-sign@0.4.0
+once@1.4.0
+path-to-regexp@0.1.3
+pinkie-promise@2.0.1
+process@0.11.10
+qs@0.6.6
+raw-body@1.3.0
+samsam@1.1.3
+semver@5.6.0
+serve-favicon@2.1.7
+shelljs@0.3.0
+spdx-correct@3.1.0
+streamsearch@0.1.2
+utils-merge@1.0.0
+when@3.4.6
+wrappy@1.0.2
+async@1.5.2
+basic-auth-connect@1.0.0
+bootstrap-submenu@2.0.4
+camelcase@2.1.1
+caseless@0.6.0
+commander@0.6.1
+cookie@0.1.2
+cookie-signature@1.0.5
+cron@1.0.4
+CSSselect@0.4.1
+debug@2.6.9
+depd@1.1.2
+diff@1.0.7
+ee-first@1.1.1
+form-data@0.1.2
+forwarded@0.1.2
+fs-extra@0.11.1
+glob@3.2.11
+growl@1.8.1
+grunt-legacy-log@0.1.3
+hooker@0.2.3
+iconv-lite@0.2.11
+imap@0.8.13
+inherits@2.0.3
+is-finite@1.0.2
+json-stringify-safe@5.0.1
+lodash@1.3.1
+map-obj@1.0.1
+meow@3.7.0
+methods@0.0.1
+mime@1.2.11
+minimist@1.2.0
+mocha@1.21.4
+multer@1.4.1
+mz@1.3.0
+optimist@0.3.7
+psl@1.1.31
+readable-stream@1.0.34
+read-pkg@1.1.0
+reduce-component@1.0.1
+repeating@2.0.1
+response-time@2.0.1
+rimraf@2.6.3
+serve-static@1.6.5
+sinon@1.10.3
+spdx-exceptions@2.2.0
+tinycolor@0.0.1
+uid-safe@1.1.0
+underscore@1.7.0
+util@0.10.4
 xmlbuilder@9.0.7
-xmlhttprequest@1.4.2
-xtend@4.0.1
-yallist@2.1.2
-yamljs@0.3.0
-yauzl@2.4.1
-zeparser@0.0.5
+accepts@1.1.4
+append-field@1.0.0
+async@2.6.1
+buffer-from@1.1.1
+bytes@1.0.0
+cli@0.6.6
+crc@3.0.0
+csv-generate@0.0.6
+ctype@0.5.3
+dateformat@1.0.2-1.2.3
+decamelize@1.2.0
+delayed-stream@0.0.5
+destroy@1.0.3
+domhandler@2.3.0
+duplexer2@0.0.2
+ejs@0.8.8
+escape-html@1.0.1
+esprima@1.0.4
+eventemitter2@0.4.14
+find-up@1.1.2
+forever-agent@0.5.2
+glob@3.2.3
+hyperquest@0.3.0
+jsonfile@1.0.1
+libqp@1.1.0
+lodash@2.4.2
+mime-db@1.37.0
+minimatch@0.3.0
+ms@0.6.2
+multiparty@3.3.2
+nodemailer-wellknown@0.1.10
+nopt@1.0.10
+number-is-nan@1.0.1
+parse-json@2.2.0
+path@0.12.7
+qs@1.2.2
+readable-stream@1.1.14
+require-all@1.0.0
+sax@0.6.1
+shelljs@0.5.3
+stream-transform@0.1.2
+superagent@0.18.0
+tunnel-agent@0.4.3
+typedarray@0.0.6
+underscore@1.9.1
+utils-merge@1.0.1
+which@1.0.9
+ws@0.4.32
+argparse@0.1.16
+aws-sign2@0.5.0
+batch@0.5.1
+body-parser@1.8.4
+bootstrap-table@1.13.1
+camelcase-keys@2.1.0
+colors@0.6.2
+commander@1.3.2
+compressible@2.0.15
+console-browserify@1.1.0
+cookie@0.1.3
+cookie-signature@1.0.6
+cryptiles@0.2.2
+CSSwhat@0.4.7
+date-now@0.1.4
+dns-sync@0.1.3
+dom-serializer@0.0.1
+error-ex@1.3.2
+express-session@1.15.6
+form-data@0.1.4
+fs-extra@0.6.4
+get-stdin@4.0.1
+glob@5.0.15
+graceful-fs@1.2.3
+grunt@0.4.5
+grunt-legacy-log-utils@0.1.1
+hawk@1.1.1
+hosted-git-info@2.7.1
+indent-string@2.1.0
+libbase64@0.1.0
+lodash@3.10.1
+merge-descriptors@0.0.2
+methods@1.0.0
+mime@1.2.5
+mime-types@1.0.2
+moment@2.23.0
+nan@1.0.0
+ncp@0.4.2
+path-type@1.1.0
+proxy-addr@1.0.1
+qs@2.2.3
+random-bytes@1.0.0
+read-pkg-up@1.0.1
+safe-buffer@5.1.2
+serve-index@1.2.1
+should@4.0.4
+spdx-expression-parse@3.0.0
+strip-bom@2.0.0
+through2@0.6.5
+uglify-js@2.4.15
+underscore.string@2.2.1
+util@0.11.1
+amdefine@1.0.1
+asn1@0.1.11
+base64-url@1.2.1
+boom@0.4.2
+buildmail@1.3.0
+cheerio@0.17.0
+clone@0.1.18
+commander@2.0.0
+concat-stream@1.6.2
+cookie@0.3.1
+crc@3.2.1
+csv-parse@1.3.3
+currently-unhandled@0.4.1
+etag@1.3.1
+express-session@1.8.2
+findup-sync@0.1.3
+glob@7.1.3
+hyperquest@1.3.0
+ipaddr.js@0.1.2
+jade@0.26.3
+jsonfile@2.4.0
+lodash@3.7.0
+lru-cache@2.7.3
+methods@1.1.0
+minimatch@1.0.0
+mkdirp@0.3.0
+mustache@0.8.2
+nodemailer@1.3.0
+nopt@3.0.1
+on-finished@2.1.0
+path-exists@2.1.0
+pify@2.3.0
+process-nextick-args@2.0.0
+qs@2.2.4
+readable-stream@2.3.6
+resolve@0.3.1
+rndm@1.1.1
+safer-buffer@2.1.2
+scmp@1.0.0
+send@0.9.2
+source-map@0.1.34
+string_decoder@0.10.31
+supertest@0.13.0
+type-is@1.5.7
+uid-safe@2.1.5
+util-deprecate@1.0.2
+vhost@3.0.2
+xml2js@0.4.19
+xtend@4.0.1
\ No newline at end of file