[openstack-dev] [heat] Problems with software config and Heat standalone configurations

Michael Elder mdelder at us.ibm.com
Fri Apr 4 01:26:06 UTC 2014


Hello,

While adopting the latest from the software configurations in Icehouse, we 
discovered an issue with the new software configuration type and its 
assumptions about using the heat client to perform behavior. 

The change was introduced in:

commit 21f60b155e4b65396ebf77e05a0ef300e7c3c1cf
Author: Steve Baker <sbaker at redhat.com>
Change: https://review.openstack.org/#/c/67621/

The net is that the software config type in software_config.py lines 
147-152 relies on the heat client to create/clone software configuration 
resources in the heat database:

    def handle_create(self):
        props = dict(self.properties)
        props[self.NAME] = self.physical_resource_name()

        sc = self.heat().software_configs.create(**props) ## HERE THE HEAT 
CLIENT IS CREATING A NEW SOFTWARE_CONFIG TO MAKE EACH ONE IMMUTABLE
        self.resource_id_set(sc.id)

My concerns with this approach:

When used in standalone mode, the Heat engine receives headers which are 
used to drive authentication (X-Auth-Url, X-Auth-User, X-Auth-Key, ..):

curl -i -X POST -H 'X-Auth-Key: password' -H 'Accept: application/json' -H 
'Content-Type: application/json' -H 'X-Auth-Url: http://[host]:5000/v2.0' 
-H 'X-Auth-User: admin' -H 'User-Agent: python-heatclient' -d '{...}' 
http://10.0.2.15:8004/v1/{tenant_id}

In this mode, the heat config file indicates standalone mode and can also 
indicate multicloud support:

# /etc/heat/heat.conf
[paste_deploy]
flavor = standalone

[auth_password]
allowed_auth_uris = http://[host1]:5000/v2.0,http://[host2]:5000/v2.0
multi_cloud = true

Any keystone URL which is referenced is unaware of the orchestration 
engine which is interacting with it. Herein lies the design flaw.

When software_config calls self.heat(), it resolves clients.py's heat 
client:

    def heat(self):
        if self._heat:
            return self._heat
 
        con = self.context
        if self.auth_token is None:
            logger.error(_("Heat connection failed, no auth_token!"))
            return None
        # try the token
        args = {
                'auth_url': con.auth_url,
                'token': self.auth_token,
                'username': None,
                'password': None,
                'ca_file': self._get_client_option('heat', 'ca_file'),
                'cert_file': self._get_client_option('heat', 'cert_file'),
                'key_file': self._get_client_option('heat', 'key_file'),
                'insecure': self._get_client_option('heat', 'insecure') 
         }

        endpoint_type = self._get_client_option('heat', 'endpoint_type')
        endpoint = self._get_heat_url()
        if not endpoint:
            endpoint = self.url_for(service_type='orchestration',
                                    endpoint_type=endpoint_type)
        self._heat = heatclient.Client('1', endpoint, **args)

        return self._heat

Here, an attempt to look up the orchestration URL (which is already 
executing in the context of the heat engine) comes up wrong because 
Keystone doesn't know about this remote standalone Heat engine. 

Further, at this point, the username and password are null, and when the 
auth_password standza is applied in the config file, Heat will deny any 
attempts at authorization which only provide a token. As I understand it 
today, that's because it doesn't have individual keystone admin users for 
all remote keystone services in the list of allowed_auth_urls. Hence, if 
only provided with a token, I don't think the heat engine can validate the 
token against the remote keystone. 

One workaround that I've implemented locally is to change the logic to 
check for standalone mode and send the username and password. 

       flavor = 'default'
        try:
            logger.info("Configuration is %s" % str(cfg.CONF))
            flavor = cfg.CONF.paste_deploy.flavor
        except cfg.NoSuchOptError as nsoe:
            flavor = 'default'
        logger.info("Flavor is %s" % flavor)
 
        # We really should examine the pipeline to determine whether we're 
using authtoken or authpassword.
        if flavor == 'standalone':
 
            context_map = self.context.to_dict()
 
            if 'username' in context_map.keys():
                username = context_map['username']
            else:
                username = None
 
            if 'password' in context_map.keys():
                password = context_map['password']
            else:
                password = None
 
            logger.info("Configuring username='%s' and password='%s'" % 
(username, password))
            args = {
                'auth_url': con.auth_url,
                'token': None,
                'username': username,
                'password': password,
                'ca_file': self._get_client_option('heat', 'ca_file'),
                'cert_file': self._get_client_option('heat', 'cert_file'),
                'key_file': self._get_client_option('heat', 'key_file'),
                'insecure': self._get_client_option('heat', 'insecure')
            } 
        else:
            if self.auth_token is None:
                logger.error(_("Heat connection failed, no auth_token!"))
                return None
...

Is this a known issue? 

-M

________________________________
Kind Regards,

Michael D. Elder

STSM | Master Inventor
mdelder at us.ibm.com  | linkedin.com/in/mdelder

"Success is not delivering a feature; success is learning how to solve the 
customer’s problem.” -Mark Cook
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.openstack.org/pipermail/openstack-dev/attachments/20140403/d8457393/attachment.html>


More information about the OpenStack-dev mailing list