diff --git a/install-sdist-to-test.py b/install-sdist-to-test.py
new file mode 100644
index 0000000000000000000000000000000000000000..403da6b47d28e7493b97e32333c0d386a95a9ca8
--- /dev/null
+++ b/install-sdist-to-test.py
@@ -0,0 +1,98 @@
+from getpass import getpass
+import os
+import logging
+import threading
+
+import click
+from paramiko import SSHClient
+from scp import SCPClient
+
+DEFAULT_HOSTNAMES = [
+    'test-inventory-provider01.geant.org',
+    'test-inventory-provider02.geant.org'
+]
+
+
+def _install_proc(hostname, username, password, sdist):
+
+    logging.info(f'installing on {hostname}')
+
+    scp_destination = f'/tmp/{os.path.basename(sdist)}'
+
+    ssh = SSHClient()
+    ssh.load_system_host_keys()
+    ssh.connect(hostname=hostname, username=username, password=password)
+    scp = SCPClient(ssh.get_transport())
+    scp.put(sdist, scp_destination)
+
+    channel = ssh.invoke_shell()
+    stdin = channel.makefile('wb')
+    stdout = channel.makefile('rb')
+
+    pip = '/home/inventory/venv/bin/pip'
+    commands = [
+        f'sudo su - -c \'{pip} uninstall -y inventory\'',
+        f'sudo su - -c \'{pip} install {scp_destination}\'',
+        f'rm {scp_destination}',
+        'exit'
+    ]
+    stdin.write('\n'.join(commands) + '\n')
+    print('\n'.join(commands))
+    print(stdout.read())
+    stdout.close()
+    stdin.close()
+
+    processes = [
+        'inventory-provider.service',
+        'inventory-worker.service',
+        'inventory-monitor.service'
+    ]
+    restart_cmd = 'sudo su - -c \'systemctl restart ' \
+        + ' '.join(processes) + '\''
+    stdin, stdout, _ = ssh.exec_command(restart_cmd)
+    output = stdout.read()
+    status = stdout.channel.recv_exit_status()
+    logging.debug(f'status: {status}, output: {output}')
+
+    ssh.close()
+
+    logging.info(f'finished installing on {hostname}')
+
+
+@click.command()
+@click.option(
+    "--hostname",
+    multiple=True,
+    default=DEFAULT_HOSTNAMES,
+    type=click.STRING,
+    help="hostname [%r]"
+         % str(DEFAULT_HOSTNAMES))
+@click.option(
+    "--user",
+    default=None,
+    type=click.STRING,
+    help="ssh username")
+@click.option(
+    "--sdist",
+    required=True,
+    type=click.Path(exists=True, dir_okay=False),
+    help="sdist filename")
+def cli(hostname, user, sdist):
+    password = getpass(prompt='Password: ', stream=None)
+
+    def _make_thread(h):
+        t = threading.Thread(
+            target=_install_proc,
+            args=[h, user, password, sdist])
+        t.start()
+        return t
+
+    threads = [_make_thread(h) for h in hostname]
+
+    for t in threads:
+        t.join()
+
+
+if __name__ == '__main__':
+    logging.basicConfig(level=logging.INFO)
+    cli()