cinder.services.list() fails with KeyError: service

Bug #1314018 reported by John Stanford
12
This bug affects 2 people
Affects Status Importance Assigned to Milestone
python-cinderclient
New
Undecided
Unassigned

Bug Description

I have python-cinderclient 1.0.9 installed, and cinder 2014.1 on CentOS 6.5. Performing cinder service list from the CLI succeeds, but using the python API fails with a KeyError: service.

Here is the output of CLI:
(goldstone)[~/devel/solinea/goldstone]$ cinder service-list
+------------------+-------------------------------+------+---------+-------+----------------------------+-----------------+
| Binary | Host | Zone | Status | State | Updated_at | Disabled Reason |
+------------------+-------------------------------+------+---------+-------+----------------------------+-----------------+
| cinder-scheduler | controller-01.lab.solinea.com | nova | enabled | up | 2014-04-29T04:59:54.000000 | None |
| cinder-volume | controller-01.lab.solinea.com | nova | enabled | up | 2014-04-29T04:59:55.000000 | None |
| cinder-volume | volume-01.lab.solinea.com | nova | enabled | up | 2014-04-29T04:59:55.000000 | None |
+------------------+-------------------------------+------+---------+-------+----------------------------+-----------------+

Here is the
In [1]: from cinderclient.v1 import client

In [2]: x = client.Client('admin', 'xyz', 'admin', 'http://redacted:35357/v2.0', service_type='volume')
In [3]: x.services.list()
Out[3]: ---------------------------------------------------------------------------
AttributeError Traceback (most recent call last)
<ipython-input-3-242ae4da0abf> in <module>()
----> 1 x.services.list()

/Users/stanford/.virtualenvs/goldstone/lib/python2.7/site-packages/IPython/core/displayhook.pyc in __call__(self, result)
    245 self.start_displayhook()
    246 self.write_output_prompt()
--> 247 format_dict, md_dict = self.compute_format_data(result)
    248 self.write_format_data(format_dict, md_dict)
    249 self.update_user_ns(result)

/Users/stanford/.virtualenvs/goldstone/lib/python2.7/site-packages/IPython/core/displayhook.pyc in compute_format_data(self, result)
    155
    156 """
--> 157 return self.shell.display_formatter.format(result)
    158
    159 def write_format_data(self, format_dict, md_dict=None):

/Users/stanford/.virtualenvs/goldstone/lib/python2.7/site-packages/IPython/core/formatters.pyc in format(self, obj, include, exclude)
    150 md = None
    151 try:
--> 152 data = formatter(obj)
    153 except:
    154 # FIXME: log the exception

/Users/stanford/.virtualenvs/goldstone/lib/python2.7/site-packages/IPython/core/formatters.pyc in __call__(self, obj)
    479 type_pprinters=self.type_printers,
    480 deferred_pprinters=self.deferred_printers)
--> 481 printer.pretty(obj)
    482 printer.flush()
    483 return stream.getvalue()

/Users/stanford/.virtualenvs/goldstone/lib/python2.7/site-packages/IPython/lib/pretty.pyc in pretty(self, obj)
    345 if cls in self.type_pprinters:
    346 # printer registered in self.type_pprinters
--> 347 return self.type_pprinters[cls](obj, self, cycle)
    348 else:
    349 # deferred printer

/Users/stanford/.virtualenvs/goldstone/lib/python2.7/site-packages/IPython/lib/pretty.pyc in inner(obj, p, cycle)
    529 p.text(',')
    530 p.breakable()
--> 531 p.pretty(x)
    532 if len(obj) == 1 and type(obj) is tuple:
    533 # Special case for 1-item tuples.

/Users/stanford/.virtualenvs/goldstone/lib/python2.7/site-packages/IPython/lib/pretty.pyc in pretty(self, obj)
    360 if callable(meth):
    361 return meth(obj, self, cycle)
--> 362 return _default_pprint(obj, self, cycle)
    363 finally:
    364 self.end_group()

/Users/stanford/.virtualenvs/goldstone/lib/python2.7/site-packages/IPython/lib/pretty.pyc in _default_pprint(obj, p, cycle)
    480 if getattr(klass, '__repr__', None) not in _baseclass_reprs:
    481 # A user-provided repr.
--> 482 p.text(repr(obj))
    483 return
    484 p.begin_group(1, '<')

/Users/stanford/.virtualenvs/goldstone/lib/python2.7/site-packages/cinderclient/v1/services.pyc in __repr__(self)
     23
     24 def __repr__(self):
---> 25 return "<Service: %s>" % self.service
     26
     27

/Users/stanford/.virtualenvs/goldstone/lib/python2.7/site-packages/cinderclient/base.pyc in __getattr__(self, k)
    269 return self.__getattr__(k)
    270
--> 271 raise AttributeError(k)
    272 else:
    273 return self.__dict__[k]

AttributeError: service

Revision history for this message
Juan Manuel Ollé (juan-m-olle) wrote :

Makes the service list call cinder return the list of services but the client tries to shows an attribute that is not contained in __repr__

IMO, a concatenation of binary@host could be used to give a name to the service

Example of list call

{u'services': [{u'binary': u'cinder-scheduler',
                u'disabled_reason': None,
                u'host': u'jmolle-Controller',
                u'state': u'up',
                u'status': u'enabled',
                u'updated_at': u'2014-05-06T13:06:54.000000',
                u'zone': u'nova'},
               {u'binary': u'cinder-backup',
                u'disabled_reason': None,
                u'host': u'jmolle-Controller',
                u'state': u'up',
                u'status': u'enabled',
                u'updated_at': u'2014-05-06T13:06:48.000000',
                u'zone': u'nova'},
               {u'binary': u'cinder-volume',
                u'disabled_reason': None,
                u'host': u'jmolle-Controller',
                u'state': u'up',
                u'status': u'enabled',
                u'updated_at': u'2014-05-06T13:06:49.000000',
                u'zone': u'nova'}]}

Any thought?

Revision history for this message
John Stanford (jxstanford) wrote :

My tendency would be to keep the __repr__ simple, and just use the name. This aligns with the pattern used by nova:

In [64]: c.services.list()
Out[64]:
[<Service: nova-consoleauth>,
 <Service: nova-conductor>,
 <Service: nova-scheduler>,
 <Service: nova-compute>,
 <Service: nova-cert>,
 <Service: nova-console>,
 <Service: nova-compute>]

Keystone has gone exactly the opposite way and uses what looks like the entire dict. I think that's way overkill. If you want the detail, process the list:

In [69]: c.services.list()
Out[69]:
[<Service {u'type': u'image', u'description': u'Openstack Image Service', u'enabled': True, u'id': u'0b0fe44b60564da492070941db2f160f', u'name': u'glance'}>,
 <Service {u'type': u'metering', u'description': u'Openstack Metering Service', u'enabled': True, u'id': u'3417cbf8ca7c40c69a191f9610d0ef30', u'name': u'ceilometer'}>,
 <Service {u'type': u'volume', u'description': u'Cinder Service', u'enabled': True, u'id': u'3833e9efab5d413e9588f1a33f61a11d', u'name': u'cinder'}>,
 <Service {u'type': u'ec2', u'description': u'EC2 Service', u'enabled': True, u'id': u'39130798096b4214980bf8aa8bc66e5a', u'name': u'nova_ec2'}>,
 <Service {u'type': u'object-store', u'description': u'Openstack Object-Store Service', u'enabled': True, u'id': u'6fc024ea4317407f8e32b80847e3bbff', u'name': u'swift'}>,
 <Service {u'type': u'network', u'description': u'Neutron Networking Service', u'enabled': True, u'id': u'7b8eb446fff84f11b6bb648738eee5c1', u'name': u'neutron'}>,
 <Service {u'type': u's3', u'description': u'Openstack S3 Service', u'enabled': True, u'id': u'99e6ab7404a34974af0b61cb1bed9e57', u'name': u'swift_s3'}>,
 <Service {u'type': u'orchestration', u'description': u'Openstack Orchestration Service', u'enabled': True, u'id': u'c8d574752dfa4c9e979e73aa99c9fdf6', u'name': u'heat'}>,
 <Service {u'type': u'identity', u'description': u'OpenStack Identity Service', u'enabled': True, u'id': u'd931233edecd460fb7e988803062271e', u'name': u'keystone'}>,
 <Service {u'type': u'compute', u'description': u'Openstack Compute Service', u'enabled': True, u'id': u'efb8e2617e8c4ac1bed2aa1072aa6e42', u'name': u'nova'}>]

I guess the question I would ask is are you going to use the repr for decision making via the API, and the answer I lean toward is no. In that case, does the addition of a hostname in __repr__ provide any value over something like this in your code which doesn't rely on a magic method directly, rather uses the API as intended:

[str(s['name'] + "@" + s['host'] for s in c.services.list()]

I have a patch submitted that just uses the binary field on https://bugs.launchpad.net/python-cinderclient/+bug/1315606. I'm curious why this got a new bug number. I'm relatively new to the process, so if anyone could help me understand, I would appreciate. Should one of them be marked as a duplicate?

To post a comment you must log in.
This report contains Public information  
Everyone can see this information.

Other bug subscribers

Remote bug watches

Bug watches keep track of this bug in other bug trackers.