SPECS/python-etcd/auth-api-compatibility.patch
18864008
 commit 7f3dd65e5dc79cc456ef58a052501ec256d5070b
 Author: Giuseppe Lavagetto <lavagetto@gmail.com>
 Date:   Mon Feb 13 14:12:39 2017 +0100
 
     Support auth API both <= 2.2.5 and >= 2.3.0
     
     Closes #210
 
 diff --git a/src/etcd/auth.py b/src/etcd/auth.py
 index 796772d..c5c7346 100644
 --- a/src/etcd/auth.py
 +++ b/src/etcd/auth.py
 @@ -14,13 +14,28 @@ class EtcdAuthBase(object):
          self.name = name
          self.uri = "{}/auth/{}s/{}".format(self.client.version_prefix,
                                             self.entity, self.name)
 +        # This will be lazily evaluated if not manually set
 +        self._legacy_api = None
 +
 +    @property
 +    def legacy_api(self):
 +        if self._legacy_api is None:
 +            # The auth API has changed between 2.2 and 2.3, true story!
 +            major, minor, _ = map(int, self.client.version.split('.'))
 +            self._legacy_api = (major < 3 and minor < 3)
 +        return self._legacy_api
 +
  
      @property
      def names(self):
          key = "{}s".format(self.entity)
          uri = "{}/auth/{}".format(self.client.version_prefix, key)
          response = self.client.api_execute(uri, self.client._MGET)
 -        return json.loads(response.data.decode('utf-8'))[key]
 +        if self.legacy_api:
 +            return json.loads(response.data.decode('utf-8'))[key]
 +        else:
 +            return [obj[self.entity]
 +                    for obj in json.loads(response.data.decode('utf-8'))[key]]
  
      def read(self):
          try:
 @@ -102,7 +117,16 @@ class EtcdUser(EtcdAuthBase):
  
      def _from_net(self, data):
          d = json.loads(data.decode('utf-8'))
 -        self.roles = d.get('roles', [])
 +        roles = d.get('roles', [])
 +        try:
 +            self.roles = roles
 +        except TypeError:
 +            # with the change of API, PUT responses are different
 +            # from GET reponses, which makes everything so funny.
 +            # Specifically, PUT responses are the same as before...
 +            if self.legacy_api:
 +                raise
 +            self.roles = [obj['role'] for obj in roles]
          self.name = d.get('user')
  
      def _to_net(self, prevobj=None):
 diff --git a/src/etcd/tests/test_auth.py b/src/etcd/tests/test_auth.py
 index 14475f9..5c8c0b0 100644
 --- a/src/etcd/tests/test_auth.py
 +++ b/src/etcd/tests/test_auth.py
 @@ -93,6 +93,10 @@ class EtcdUserTest(TestEtcdAuthBase):
          self.assertEquals(u.roles, set(['guest', 'root']))
          # set roles as a list, it works!
          u.roles = ['guest', 'test_group']
 +        # We need this or the new API will return an internal error
 +        r = auth.EtcdRole(self.client, 'test_group')
 +        r.acls = {'*': 'R', '/test/*': 'RW'}
 +        r.write()
          try:
              u.write()
          except: