[Openstack] cfg usage - option registration, global objects

Duncan McGreggor duncan at dreamhost.com
Tue Jun 5 16:48:26 UTC 2012


+1 :-)

d

On Fri, Jun 1, 2012 at 10:37 AM, Mark Washenberger
<mark.washenberger at rackspace.com> wrote:
> Hi Mark,
>
> Please forgive the top-posting! I always get way too wordy with
> inline replies.
>
> Regarding configuration, I think there is another option I'd like us
> to adopt. We should implement the code as in your option #1, but then
> implement convenience factories that give the appearance of option #3
> or #2, or both, you pick. From your examples it might look something
> like this:
>
>    class Connection(object):
>
>        def __init__(self, broker_hostname, broker_port):
>            self.cnx = self.connect(broker_hostname, broker_port)
>
>        def cast(self, topic, msg):
>            self.cnx.cast(topic, msg)
>
>    def connection_from_global_conf():
>        return Connection(CONF.broker_hostname, CONF.broker_port)
>
> I think its pretty necessary that we don't do option #3 directly.
> There are some important use cases to consider, like migrating from
> one rpc implementation to another where you might want an adapter
> that can relay messages from one to the other. Also, cells with
> kombu at least requires that one process be able to talk to multiple
> brokers.
>
> Regarding incubation, I suppose I am confused. At what point during
> incubation do other projects start to use the shared library? I would
> imagine the answer to be "after incubation" but it sounds like there
> are several projects very eager to adopt rpc as soon as it lands in
> openstack common, even before incubation is complete.
>
> If incubation happens before the calcifying effects of shared use
> set in, then it sounds like a great place to address the other
> rpc-specific concerns we've talked about. Otherwise I guess we're
> stuck where I thought we were, where the bar needs to be set pretty
> high to initially land in os-common.
>
> "Mark McLoughlin" <markmc at redhat.com> said:
>
>> Hi Mark,
>>
>> On Thu, 2012-05-31 at 10:48 -0400, Mark Washenberger wrote:
>>>
>>> "Jay Pipes" <jaypipes at gmail.com> said:
>>> > On 05/29/2012 04:04 AM, Mark McLoughlin wrote:
>>> >> Adopting this pattern across all projects will actually help
>>> >> openstack-common more generally. For example, Russell is moving the RPC
>>> >> code into openstack-common and it has a bunch of configuration options.
>>> >> If it can assume a global configuration object, things become much
>>> >> easier.
>>> >
>>> > Unfortunately, what this leads to is interdependencies between the
>>> > openstack-common-rpc code and the openstack-common-cfg code. :( Now, if
>>> > someone wants to use the openstack RPC code in their own project, they
>>> > have to switch their way of configuring stuff to use global config
>>> > objects. Tight coupling means less adherence to the "do one thing and do
>>> > it well" mantra of *nix utilities and libraries and in general isn't
>>> > good software design.
>>>
>>>
>>> I personally would consider a rigid connection between the rpc library and
>>> the configuration to be inappropriate in the context of openstack common.
>>
>> This is a fairly general design question for openstack-common.
>>
>> If the behaviour of any given API should be dependent on the
>> configuration of the service (i.e. in nova.conf, glance-api.conf,
>> keystone.conf), then how should we design the API to handle that?
>>
>> Three options:
>>
>>   1) The API knows nothing about cfg:
>>
>>      class Connection(object):
>>
>>          def __init__(self, broker_hostname, broker_port):
>>              self.cnx = self.connect(broker_hostname, broker_port)
>>
>>          def cast(self, topic, msg):
>>              self.cnx.cast(topic, msg)
>>
>>   2) The API is passed a ConfigOpts instance:
>>
>>      class Connection(object):
>>
>>          def __init__(self, conf):
>>              self.cnx = self.connect(conf.broker_hostname,
>>                                      conf.broker_port)
>>
>>          def cast(self, topic, msg):
>>              self.cnx.cast(topic, msg)
>>
>>   3) The API uses the global config object
>>
>>      class Connection(object):
>>
>>          def __init__(self):
>>              self.cnx = self.connect(CONF.broker_hostname,
>>                                      CONF.broker_port)
>>
>>          def cast(self, topic, msg):
>>              self.cnx.cast(topic, msg)
>>
>>
>> I see (1) as having value if we want the API to be usable outside
>> OpenStack. That might be worthwhile long term, but openstack-common's
>> goal is to provide APIs shared between OpenStack projects.
>>
>> (2) and (3) have the huge benefit of configuration consistency - the
>> same configuration keys, defaults, etc. shared across projects.
>>
>> (2) has value if there are cases where we want to use a non-global cfg
>> object. Quantum might have this use case if it continues parsing plugin
>> configuration separately from its main configuration. We'll see.
>>
>> (3) has value if all use cases are using a global object.
>>
>> I can see us getting to a point where we support both (2) and (3). I'm
>> dubious of the value of (1) in the medium term, but maybe we might find
>> a compelling use case for it.
>>
>>> I'm also very happy to contribute modifications that would eliminate that
>>> connection.
>>>
>>> There are a few other reasons I'm concerned about nova's rpc implementation
>>> becoming the de facto standard. It has grown up organically and as such has
>>> some significant issues we should probably address before we create a
>>> precedent that other projects must adopt it to be good community members.
>>
>> "other projects must adopt it to be good community members" - that's an
>> interesting take, not the way I'd put it.
>>
>> I think I'd say that if a project wants to do RPC, it makes more sense
>> to improve the RPC API in openstack-common to meet its needs rather than
>> start a from-scratch implementation or, worse, copy and paste what's
>> there and customize it.
>>
>>> From a brief scan, it seems to me that a restructured implementation of rpc
>>> that lands in common should
>>>
>>>  * not be tied up with eventlet on the consumer side
>>
>> Sounds like a good and achievable goal. Is there or will there soon be
>> an OpenStack project that needs has this requirement in order to be able
>> to use this code?
>>
>>>  * let the consumer code decide when to ack a message
>>>    (although maybe the concept of acking doesn't exist for all implementations?)
>>
>> What's the use case?
>>
>>>  * not depend on a global singleton _RPC_IMPL
>>
>> I agree.
>>
>>>  * leave out/refactor some unused or non-general aspects, such as multicall,
>>>    fanout_cast_to_server, notify, and fanout_cast (not so sure about that last
>>> one)
>>
>> i.e. leave out stuff that is specific to Nova? How about if e.g. Cinder
>> was using it?
>>
>>
>> Don't forget that openstack-common has this notion of "incubating" APIs.
>> Everything is in incubation at the moment. I'd say cfg is the closest to
>> coming out of incubation.
>>
>> I expect to do a pretty detailed review of the patch to add rpc to
>> openstack-common and make some API design recommendations. But I think
>> we'll have to balance some of those design ideas between "stuff we
>> really should fix before it goes into openstack-common" vs "stuff that
>> would need to be fixed before the API comes out of incubation".
>>
>> Cheers,
>> Mark.
>>
>>
>
>
>
> _______________________________________________
> Mailing list: https://launchpad.net/~openstack
> Post to     : openstack at lists.launchpad.net
> Unsubscribe : https://launchpad.net/~openstack
> More help   : https://help.launchpad.net/ListHelp




More information about the Openstack mailing list