[ARVADOS] updated: 132bbb69970640e2906bc1285bee9709accb3fc7

git at public.curoverse.com git at public.curoverse.com
Sun Aug 9 01:05:11 EDT 2015


Summary of changes:
 sdk/pam/.dockerignore                       |   8 ++
 sdk/pam/Dockerfile                          |  15 +++
 sdk/pam/arvados_pam/__init__.py             |  23 +++--
 sdk/pam/debian/arvados_pam                  |  10 --
 sdk/pam/debian/shellinabox                  | 136 ----------------------------
 sdk/pam/examples/etc_pam.d_arvados-pam-test |   3 +
 sdk/pam/examples/etc_pam.d_shellinabox      |  25 +++++
 sdk/pam/examples/pam-auth-update_arvados    |  11 +++
 sdk/pam/setup.py                            |  12 ++-
 sdk/pam/tests/test_integration.py           |  23 +++++
 sdk/pam/tests/test_pam.py                   |  70 +++++---------
 11 files changed, 126 insertions(+), 210 deletions(-)
 create mode 100644 sdk/pam/.dockerignore
 create mode 100644 sdk/pam/Dockerfile
 delete mode 100644 sdk/pam/debian/arvados_pam
 delete mode 100644 sdk/pam/debian/shellinabox
 create mode 100644 sdk/pam/examples/etc_pam.d_arvados-pam-test
 create mode 100644 sdk/pam/examples/etc_pam.d_shellinabox
 create mode 100644 sdk/pam/examples/pam-auth-update_arvados
 mode change 100644 => 100755 sdk/pam/setup.py
 create mode 100644 sdk/pam/tests/test_integration.py

       via  132bbb69970640e2906bc1285bee9709accb3fc7 (commit)
      from  507110dc0aa1329ac4e5aad59c347a49e9f77364 (commit)

Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.


commit 132bbb69970640e2906bc1285bee9709accb3fc7
Author: Tom Clegg <tom at curoverse.com>
Date:   Sun Aug 9 01:05:05 2015 -0400

    6934: Load config from pam conf instead of yaml. Add docker/integration tests and example configs.

diff --git a/sdk/pam/.dockerignore b/sdk/pam/.dockerignore
new file mode 100644
index 0000000..d6778dc
--- /dev/null
+++ b/sdk/pam/.dockerignore
@@ -0,0 +1,8 @@
+*~
+*.pyc
+.eggs
+*.egg_info
+build
+debian
+dist
+tmp
diff --git a/sdk/pam/Dockerfile b/sdk/pam/Dockerfile
new file mode 100644
index 0000000..7c45607
--- /dev/null
+++ b/sdk/pam/Dockerfile
@@ -0,0 +1,15 @@
+FROM debian:wheezy
+RUN apt-get update
+RUN apt-get -qy dist-upgrade
+RUN apt-get -qy install python python-virtualenv libpam-python rsyslog
+# Packages required by pycurl, ciso8601
+RUN apt-get -qy install libcurl4-gnutls-dev python2.7-dev
+RUN pip install --upgrade setuptools
+RUN pip install python-pam
+ADD . /pam
+WORKDIR /pam
+RUN ./setup.py sdist
+RUN pip install dist/arvados-pam-*.tar.gz
+COPY examples/pam-auth-update_arvados /usr/share/pam-configs/arvados
+RUN DEBIAN_FRONTEND=noninteractive pam-auth-update arvados --remove unix
+CMD rsyslogd & tail -F /var/log/auth.log & bash
diff --git a/sdk/pam/arvados_pam/__init__.py b/sdk/pam/arvados_pam/__init__.py
index c002f3e..920a364 100644
--- a/sdk/pam/arvados_pam/__init__.py
+++ b/sdk/pam/arvados_pam/__init__.py
@@ -4,20 +4,13 @@ sys.argv=['']
 import arvados
 import os
 import syslog
-import yaml
 
 def auth_log(msg):
-    """Send errors to default auth log"""
+    """Log an authentication result to syslogd"""
     syslog.openlog(facility=syslog.LOG_AUTH)
     syslog.syslog('arvados_pam: ' + msg)
     syslog.closelog()
 
-def config_file():
-    return file('/etc/default/arvados_pam.conf').read()
-
-def config():
-    return yaml.load(config_file())
-
 class AuthEvent(object):
     def __init__(self, config, service, client_host, username, token):
         self.config = config
@@ -34,10 +27,10 @@ class AuthEvent(object):
         """Return truthy IFF credentials should be accepted."""
         ok = False
         try:
-            self.api_host = self.config[self.service]['ARVADOS_API_HOST']
+            self.api_host = self.config['arvados_api_host']
             self.arv = arvados.api('v1', host=self.api_host, token=self.token, cache=None)
 
-            vmname = self.config[self.service]['virtual_machine_hostname']
+            vmname = self.config['virtual_machine_hostname']
             vms = self.arv.virtual_machines().list(filters=[['hostname','=',vmname]]).execute()
             if vms['items_available'] > 1:
                 raise Exception("lookup hostname %s returned %d records" % (vmname, vms['items_available']))
@@ -98,6 +91,11 @@ class AuthEvent(object):
 
 
 def pam_sm_authenticate(pamh, flags, argv):
+    config = {}
+    config['arvados_api_host'] = argv[1]
+    config['virtual_machine_hostname'] = argv[2]
+    config['noprompt'] = (len(argv) > 3 and argv[3] == 'noprompt')
+
     try:
         username = pamh.get_user()
     except pamh.exception as e:
@@ -107,11 +105,12 @@ def pam_sm_authenticate(pamh, flags, argv):
         return pamh.PAM_USER_UNKNOWN
 
     try:
-        token = pamh.conversation(pamh.Message(pamh.PAM_PROMPT_ECHO_OFF, '')).resp
+        prompt = '' if config['noprompt'] else 'Arvados API token: '
+        token = pamh.conversation(pamh.Message(pamh.PAM_PROMPT_ECHO_OFF, prompt)).resp
     except pamh.exception as e:
         return e.pam_result
 
-    if AuthEvent(config(),
+    if AuthEvent(config,
                  service=pamh.service,
                  client_host=pamh.rhost,
                  username=username,
diff --git a/sdk/pam/debian/arvados_pam b/sdk/pam/debian/arvados_pam
deleted file mode 100644
index eae61d9..0000000
--- a/sdk/pam/debian/arvados_pam
+++ /dev/null
@@ -1,10 +0,0 @@
-# Default values for libpam arvados module
-#
-# ARVADOS_API_HOST should be te api hosts.
-# should be reachable, and will be called
-# from arvados_pam.py using Arvados Python SDK
-ARVADOS_API_HOST=zzzzz.arvadosapi.com
-
-# HOSTNAME is the hostname as is stored in the API object
-# something like "foo.shell" or "shell", but not"foo.shell.zzzzz.arvadosapi.com"!
-HOSTNAME=shell
diff --git a/sdk/pam/debian/shellinabox b/sdk/pam/debian/shellinabox
deleted file mode 100644
index b983728..0000000
--- a/sdk/pam/debian/shellinabox
+++ /dev/null
@@ -1,136 +0,0 @@
-#
-# The PAM configuration file for the Shadow `login' service
-#
-
-# Enforce a minimal delay in case of failure (in microseconds).
-# (Replaces the `FAIL_DELAY' setting from login.defs)
-# Note that other modules may require another minimal delay. (for example,
-# to disable any delay, you should add the nodelay option to pam_unix)
-#auth       optional   pam_faildelay.so  delay=3000000
-auth       optional   pam_faildelay.so  delay=0
-
-# Outputs an issue file prior to each login prompt (Replaces the
-# ISSUE_FILE option from login.defs). Uncomment for use
-# auth       required   pam_issue.so issue=/etc/issue
-
-# Disallows root logins except on tty's listed in /etc/securetty
-# (Replaces the `CONSOLE' setting from login.defs)
-#
-# With the default control of this module:
-#   [success=ok new_authtok_reqd=ok ignore=ignore user_unknown=bad default=die]
-# root will not be prompted for a password on insecure lines.
-# if an invalid username is entered, a password is prompted (but login
-# will eventually be rejected)
-#
-# You can change it to a "requisite" module if you think root may mis-type
-# her login and should not be prompted for a password in that case. But
-# this will leave the system as vulnerable to user enumeration attacks.
-#
-# You can change it to a "required" module if you think it permits to
-# guess valid user names of your system (invalid user names are considered
-# as possibly being root on insecure lines), but root passwords may be
-# communicated over insecure lines.
-auth [success=ok new_authtok_reqd=ok ignore=ignore user_unknown=bad default=die] pam_securetty.so
-
-# Disallows other than root logins when /etc/nologin exists
-# (Replaces the `NOLOGINS_FILE' option from login.defs)
-auth       requisite  pam_nologin.so
-
-# SELinux needs to be the first session rule. This ensures that any
-# lingering context has been cleared. Without out this it is possible
-# that a module could execute code in the wrong domain.
-# When the module is present, "required" would be sufficient (When SELinux
-# is disabled, this returns success.)
-session [success=ok ignore=ignore module_unknown=ignore default=bad] pam_selinux.so close
-
-# This module parses environment configuration file(s)
-# and also allows you to use an extended config
-# file /etc/security/pam_env.conf.
-#
-# parsing /etc/environment needs "readenv=1"
-session       required   pam_env.so readenv=1
-# locale variables are also kept into /etc/default/locale in etch
-# reading this file *in addition to /etc/environment* does not hurt
-session       required   pam_env.so readenv=1 envfile=/etc/default/locale
-
-
-#
-# /etc/pam.d/common-auth - authentication settings common to all services
-#
-# This file is included from other service-specific PAM config files,
-# and should contain a list of the authentication modules that define
-# the central authentication scheme for use on the system
-# (e.g., /etc/shadow, LDAP, Kerberos, etc.).  The default is to use the
-# traditional Unix authentication mechanisms.
-#
-# As of pam 1.0.1-6, this file is managed by pam-auth-update by default.
-# To take advantage of this, it is recommended that you configure any
-# local modules either before or after the default block, and use
-# pam-auth-update to manage selection of other modules.  See
-# pam-auth-update(8) for details.
-
-# here are the per-package modules (the "Primary" block)
-auth  [success=1 default=ignore] pam_python.so /usr/bin/arvados_pam.py
-# here's the fallback if no module succeeds
-auth	requisite			pam_deny.so
-# prime the stack with a positive return value if there isn't one already;
-# this avoids us returning an error just because nothing sets a success code
-# since the modules above will each just jump around
-auth	required			pam_permit.so
-# and here are more per-package modules (the "Additional" block)
-auth	optional	pam_ecryptfs.so unwrap
-# end of pam-auth-update config
-
-# This allows certain extra groups to be granted to a user
-# based on things like time of day, tty, service, and user.
-# Please edit /etc/security/group.conf to fit your needs
-# (Replaces the `CONSOLE_GROUPS' option in login.defs)
-auth       optional   pam_group.so
-
-# Uncomment and edit /etc/security/time.conf if you need to set
-# time restrainst on logins.
-# (Replaces the `PORTTIME_CHECKS_ENAB' option from login.defs
-# as well as /etc/porttime)
-# account    requisite  pam_time.so
-
-# Uncomment and edit /etc/security/access.conf if you need to
-# set access limits.
-# (Replaces /etc/login.access file)
-# account  required       pam_access.so
-
-# Sets up user limits according to /etc/security/limits.conf
-# (Replaces the use of /etc/limits in old login)
-session    required   pam_limits.so
-
-# Prints the last login info upon succesful login
-# (Replaces the `LASTLOG_ENAB' option from login.defs)
-session    optional   pam_lastlog.so
-
-# Prints the message of the day upon succesful login.
-# (Replaces the `MOTD_FILE' option in login.defs)
-# This includes a dynamically generated part from /run/motd.dynamic
-# and a static (admin-editable) part from /etc/motd.
-session    optional   pam_motd.so  motd=/run/motd.dynamic
-session    optional   pam_motd.so
-
-# Prints the status of the user's mailbox upon succesful login
-# (Replaces the `MAIL_CHECK_ENAB' option from login.defs).
-#
-# This also defines the MAIL environment variable
-# However, userdel also needs MAIL_DIR and MAIL_FILE variables
-# in /etc/login.defs to make sure that removing a user
-# also removes the user's mail spool file.
-# See comments in /etc/login.defs
-session    optional   pam_mail.so standard
-
-# Standard Un*x account and session
- at include common-account
- at include common-session
- at include common-password
-
-# SELinux needs to intervene at login time to ensure that the process
-# starts in the proper default security context. Only sessions which are
-# intended to run in the user's context should be run after this.
-session [success=ok ignore=ignore module_unknown=ignore default=bad] pam_selinux.so open
-# When the module is present, "required" would be sufficient (When SELinux
-# is disabled, this returns success.)
diff --git a/sdk/pam/examples/etc_pam.d_arvados-pam-test b/sdk/pam/examples/etc_pam.d_arvados-pam-test
new file mode 100644
index 0000000..ddff8c7
--- /dev/null
+++ b/sdk/pam/examples/etc_pam.d_arvados-pam-test
@@ -0,0 +1,3 @@
+auth [success=1 default=ignore] pam_python.so /usr/local/lib/python2.7/dist-packages/arvados_pam/__init__.py abc.example testvm2.shell
+auth	requisite			pam_deny.so
+auth	required			pam_permit.so
diff --git a/sdk/pam/examples/etc_pam.d_shellinabox b/sdk/pam/examples/etc_pam.d_shellinabox
new file mode 100644
index 0000000..355a85f
--- /dev/null
+++ b/sdk/pam/examples/etc_pam.d_shellinabox
@@ -0,0 +1,25 @@
+# Install in /etc/pam.d/shellinabox
+
+auth       optional   pam_faildelay.so  delay=3000000
+auth [success=ok new_authtok_reqd=ok ignore=ignore user_unknown=bad default=die] pam_securetty.so
+auth       requisite  pam_nologin.so
+session [success=ok ignore=ignore module_unknown=ignore default=bad] pam_selinux.so close
+session       required   pam_env.so readenv=1
+session       required   pam_env.so readenv=1 envfile=/etc/default/locale
+
+auth [success=1 default=ignore] pam_python.so /usr/local/lib/python2.7/dist-packages/arvados_pam/__init__.py api.example shell.example noprompt
+auth	requisite			pam_deny.so
+auth	required			pam_permit.so
+
+auth       optional   pam_group.so
+session    required   pam_limits.so
+session    optional   pam_lastlog.so
+session    optional   pam_motd.so  motd=/run/motd.dynamic
+session    optional   pam_motd.so
+session    optional   pam_mail.so standard
+
+ at include common-account
+ at include common-session
+ at include common-password
+
+session [success=ok ignore=ignore module_unknown=ignore default=bad] pam_selinux.so open
diff --git a/sdk/pam/examples/pam-auth-update_arvados b/sdk/pam/examples/pam-auth-update_arvados
new file mode 100644
index 0000000..eb58694
--- /dev/null
+++ b/sdk/pam/examples/pam-auth-update_arvados
@@ -0,0 +1,11 @@
+# 1. Install in /usr/share/pam-configs/arvados
+# 2. Run `pam-auth-update arvados`
+
+Name: Arvados authentication
+Default: yes
+Priority: 256
+Auth-Type: Primary
+Auth:
+	[success=end default=ignore]	pam_python.so /usr/local/lib/python2.7/dist-packages/arvados_pam/__init__.py api.example shell.example
+Auth-Initial:
+	[success=end default=ignore]	pam_python.so /usr/local/lib/python2.7/dist-packages/arvados_pam/__init__.py api.example shell.example
diff --git a/sdk/pam/setup.py b/sdk/pam/setup.py
old mode 100644
new mode 100755
index 4942e2d..f8a0c62
--- a/sdk/pam/setup.py
+++ b/sdk/pam/setup.py
@@ -3,17 +3,20 @@
 import os
 import sys
 import setuptools.command.egg_info as egg_info_cmd
+import subprocess
 
 from setuptools import setup, find_packages
 
 SETUP_DIR = os.path.dirname(__file__) or '.'
 README = os.path.join(SETUP_DIR, 'README.rst')
 
+tagger = egg_info_cmd.egg_info
 try:
     import gittaggers
-    tagger = gittaggers.EggInfoFromGit
-except ImportError:
-    tagger = egg_info_cmd.egg_info
+    if subprocess.check_call(['git', 'log', '-n1']):
+        tagger = gittaggers.EggInfoFromGit
+except (ImportError, OSError):
+    pass
 
 setup(name='arvados-pam',
       version='0.1',
@@ -31,10 +34,9 @@ setup(name='arvados-pam',
       ],
       install_requires=[
           'arvados-python-client>=0.1.20150801000000',
-          'pyyaml',
       ],
       test_suite='tests',
-      tests_require=['mock>=1.0', 'PyYAML'],
+      tests_require=['mock>=1.0', 'python-pam'],
       zip_safe=False,
       cmdclass={'egg_info': tagger},
       )
diff --git a/sdk/pam/tests/test_integration.py b/sdk/pam/tests/test_integration.py
new file mode 100644
index 0000000..2728bcd
--- /dev/null
+++ b/sdk/pam/tests/test_integration.py
@@ -0,0 +1,23 @@
+import os
+if os.path.exists('/etc/pam.d/arvados-pam-test'):
+    import pam
+    import unittest
+
+    ACTIVE_TOKEN = '3kg6k6lzmp9kj5cpkcoxie963cmvjahbt2fod9zru30k1jqdmi'
+    SPECTATOR_TOKEN = 'zw2f4gwx8hw8cjre7yp6v1zylhrhn3m5gvjq73rtpwhmknrybu'
+
+    class IntegrationTest(unittest.TestCase):
+        def setUp(self):
+            self.p = pam.pam()
+
+        def test_allow(self):
+            self.assertTrue(self.p.authenticate('active', ACTIVE_TOKEN, service='arvados-pam-test'))
+
+        def test_deny_service(self):
+            self.assertFalse(self.p.authenticate('active', ACTIVE_TOKEN, service='login'))
+
+        def test_deny_token(self):
+            self.assertFalse(self.p.authenticate('active', 'bogustoken', service='arvados-pam-test'))
+
+        def test_deny_permission(self):
+            self.assertFalse(self.p.authenticate('spectator', SPECTATOR_TOKEN, service='arvados-pam-test'))
diff --git a/sdk/pam/tests/test_pam.py b/sdk/pam/tests/test_pam.py
index 70956c9..c9c0c36 100644
--- a/sdk/pam/tests/test_pam.py
+++ b/sdk/pam/tests/test_pam.py
@@ -1,45 +1,25 @@
-#!/usr/bin/env python
-
 import arvados
 import arvados_pam
 import mock
+import os
 import re
 import StringIO
 import unittest
 
-class ConfigTest(unittest.TestCase):
-    def test_ok_config(self):
-        self.assertConfig(
-            """servicename:
-              ARVADOS_API_HOST: xyzzy.example
-              virtual_machine_hostname: foo.shell
-            """, 'servicename', 'xyzzy.example', 'foo.shell')
-
-    @mock.patch('arvados_pam.config_file')
-    def assertConfig(self, txt, svcname, apihost, shellhost, config_file):
-        configfake = StringIO.StringIO(txt)
-        config_file.side_effect = [configfake]
-        c = arvados_pam.config()
-        self.assertEqual(apihost, c[svcname]['ARVADOS_API_HOST'])
-        self.assertEqual(shellhost, c[svcname]['virtual_machine_hostname'])
+ACTIVE_TOKEN = '3kg6k6lzmp9kj5cpkcoxie963cmvjahbt2fod9zru30k1jqdmi'
 
 class AuthTest(unittest.TestCase):
-
     default_config = {
-        'test_service': {
-            'ARVADOS_API_HOST': 'zzzzz.api_host.example',
-            'virtual_machine_hostname': 'testvm2.shell',
-        }
+        'ARVADOS_API_HOST': 'zzzzz.api_host.example',
+        'virtual_machine_hostname': 'testvm2.shell',
     }
-
     default_request = {
         'client_host': '::1',
-        'token': '3kg6k6lzmp9kj5cpkcoxie963cmvjahbt2fod9zru30k1jqdmi',
+        'token': ACTIVE_TOKEN,
         'username': 'active',
     }
-
     default_response = {
-        'links': lambda: {
+        'links': {
             'items': [{
                 'uuid': 'zzzzz-o0j2j-rah2ya1ohx9xaev',
                 'tail_uuid': 'zzzzz-tpzed-xurymjxw79nv3jz',
@@ -51,11 +31,11 @@ class AuthTest(unittest.TestCase):
                 },
             }],
         },
-        'users': lambda: {
+        'users': {
             'uuid': 'zzzzz-tpzed-xurymjxw79nv3jz',
             'full_name': 'Active User',
         },
-        'virtual_machines': lambda: {
+        'virtual_machines': {
             'items': [{
                 'uuid': 'zzzzz-2x53u-382brsig8rp3065',
                 'hostname': 'testvm2.shell',
@@ -70,34 +50,33 @@ class AuthTest(unittest.TestCase):
     def test_success(self):
         self.assertTrue(self.attempt())
 
-        cfg = self.config['test_service']
         self.api_client.virtual_machines().list.assert_called_with(
-            filters=[['hostname','=',cfg['virtual_machine_hostname']]])
+            filters=[['hostname','=',self.config['virtual_machine_hostname']]])
         self.api.assert_called_with(
-            'v1', host=cfg['ARVADOS_API_HOST'], token=self.request['token'], cache=None)
+            'v1', host=self.config['ARVADOS_API_HOST'], token=self.request['token'], cache=None)
         self.assertEqual(1, len(self.syslogged))
         for i in ['test_service',
                   self.request['username'],
-                  self.config['test_service']['ARVADOS_API_HOST'],
-                  self.response['virtual_machines']()['items'][0]['uuid']]:
+                  self.config['ARVADOS_API_HOST'],
+                  self.response['virtual_machines']['items'][0]['uuid']]:
             self.assertRegexpMatches(self.syslogged[0], re.escape(i))
         self.assertRegexpMatches(self.syslogged[0], re.escape(self.request['token'][0:15]), 'token prefix not logged')
         self.assertNotRegexpMatches(self.syslogged[0], re.escape(self.request['token'][15:30]), 'too much token logged')
 
     def test_fail_vm_lookup(self):
-        self.response['virtual_machines'] = self._raise
+        self.api_client.virtual_machines().list().execute.side_effect = Exception("Test-induced failure")
         self.assertFalse(self.attempt())
         self.assertRegexpMatches(self.syslogged[0], 'Test-induced failure')
 
     def test_vm_hostname_not_found(self):
-        self.response['virtual_machines'] = lambda: {
+        self.response['virtual_machines'] = {
             'items': [],
             'items_available': 0,
         }
         self.assertFalse(self.attempt())
 
     def test_vm_hostname_ambiguous(self):
-        self.response['virtual_machines'] = lambda: {
+        self.response['virtual_machines'] = {
             'items': [
                 {
                     'uuid': 'zzzzz-2x53u-382brsig8rp3065',
@@ -113,7 +92,7 @@ class AuthTest(unittest.TestCase):
         self.assertFalse(self.attempt())
 
     def test_server_ignores_vm_filters(self):
-        self.response['virtual_machines'] = lambda: {
+        self.response['virtual_machines'] = {
             'items': [
                 {
                     'uuid': 'zzzzz-2x53u-382brsig8rp3065',
@@ -125,21 +104,21 @@ class AuthTest(unittest.TestCase):
         self.assertFalse(self.attempt())
 
     def test_fail_user_lookup(self):
-        self.response['users'] = self._raise
+        self.api_client.users().current().execute.side_effect = Exception("Test-induced failure")
         self.assertFalse(self.attempt())
 
     def test_fail_permission_check(self):
-        self.response['links'] = self._raise
+        self.api_client.links().list().execute.side_effect = Exception("Test-induced failure")
         self.assertFalse(self.attempt())
 
     def test_no_login_permission(self):
-        self.response['links'] = lambda: {
+        self.response['links'] = {
             'items': [],
         }
         self.assertFalse(self.attempt())
 
     def test_server_ignores_permission_filters(self):
-        self.response['links'] = lambda: {
+        self.response['links'] = {
             'items': [{
                 'uuid': 'zzzzz-o0j2j-rah2ya1ohx9xaev',
                 'tail_uuid': 'zzzzz-tpzed-xurymjxw79nv3jz',
@@ -158,9 +137,9 @@ class AuthTest(unittest.TestCase):
         self.request = self.default_request.copy()
         self.response = self.default_response.copy()
         self.api_client = mock.MagicMock(name='api_client')
-        self.api_client.users().current().execute.side_effect = lambda: self.response['users']()
-        self.api_client.virtual_machines().list().execute.side_effect = lambda: self.response['virtual_machines']()
-        self.api_client.links().list().execute.side_effect = lambda: self.response['links']()
+        self.api_client.users().current().execute.side_effect = lambda: self.response['users']
+        self.api_client.virtual_machines().list().execute.side_effect = lambda: self.response['virtual_machines']
+        self.api_client.links().list().execute.side_effect = lambda: self.response['links']
         patcher = mock.patch('arvados.api')
         self.api = patcher.start()
         self.addCleanup(patcher.stop)
@@ -171,6 +150,3 @@ class AuthTest(unittest.TestCase):
         self.syslog = patcher.start()
         self.addCleanup(patcher.stop)
         self.syslog.side_effect = lambda s: self.syslogged.append(s)
-
-    def _raise(self, exception=Exception("Test-induced failure"), *args, **kwargs):
-        raise exception

-----------------------------------------------------------------------


hooks/post-receive
-- 




More information about the arvados-commits mailing list