I'm not sure if I'm using this the correct way. I have one class defining the required_keys and the provide_data for the same relationship. The following code excecutes provide_data on a relation join/change, but doesn't relation-set namenode_sshkey. If I remove the required_keys line, the code suddenly works (but then I can't use this class to specify the required-data for the relationship).

[...]
    {
        'service': 'namenode',
        'ports': [9000, 50070],  # ports to open after start
        'provided_data': [
            NamenodeRelation()
        ],
        'required_data': [
            NamenodeRelation(),
            {'role' : 'namenode', 'command' : 'hadoop-daemon.sh'}
        ],
        'data_ready': [
            configure_namenode,
            helpers.render_template(
                 source='upstart.conf',
                 target='/etc/init/namenode.conf')
        ],
    },
[...]


class NamenodeRelation(RelationContext):
    name = 'namenode'
    interface = 'dfs'

    def __init__(self, *args, **kwargs):
        self.required_keys = ['slave_IP', 'private-address']
        RelationContext.__init__(self,name=self.name, *args, **kwargs)

    def provide_data(self):
        return {'namenode_sshkey' : get_ssh_key() }

Is this behaviour intended or is this a bug?

share|improve this question
up vote 3 down vote accepted

That is indeed a bug. I ran into it this week while rewriting a charm using the Services framework. I'm working on a fix for it, but in the meantime, I do have a workaround.

In the ServiceManager setup, pass the key=value that you want to send over the relation wire, and don't pass anything for the required_data relation.

def manage():
    manager = ServiceManager([
        {
            'service': 'example',
            'ports': [80],  # ports to after start
            'provided_data': [
                RabbitMQRelation(username='example', vhost='/')
            ],
            'required_data': [
               RabbitMQRelation(),
            ],
            'data_ready': [
                configure_rabbitmq,
            ],
            'data_lost': [
            ],
        },
    ])
    manager.manage()

The Relation class basically short-circuits the required_keys by only setting it if there's no provided data to handle.

class RabbitMQRelation(helpers.RelationContext):
    name = 'amqp'
    interface = 'rabbitmq'

    vhost = None
    username = None
    required_keys = []

    def __init__(self, username=None, vhost=None):
        """
        This works around a bug with the RelationContext class that expects
        the required keys to be set before it will call provide_data.
        """
        if username and vhost:
            self.username = username
            self.vhost = vhost
        else:
            self.required_keys = ['private-address', 'hostname', 'password']

        super(RabbitMQRelation, self).__init__(self.name)
share|improve this answer

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.