<font size=2 face="sans-serif">No problem. </font>
<br>
<br><font size=2 face="sans-serif">Filed here: </font><a href="https://bugs.launchpad.net/heat/+bug/1302578"><font size=2 color=blue face="sans-serif">https://bugs.launchpad.net/heat/+bug/1302578</font></a><font size=2 face="sans-serif">
for continued discussion. </font>
<br>
<br><font size=2 face="sans-serif">-M</font>
<br><font size=2 face="sans-serif"><br>
________________________________<br>
Kind Regards,<br>
<br>
Michael D. Elder<br>
<br>
STSM | Master Inventor<br>
mdelder@us.ibm.com  | linkedin.com/in/mdelder<br>
<br>
"Success is not delivering a feature; success is learning how to solve
the customer’s problem.” -Mark Cook</font>
<br>
<br>
<br>
<br><font size=1 color=#5f5f5f face="sans-serif">From:      
 </font><font size=1 face="sans-serif">Steve Baker <sbaker@redhat.com></font>
<br><font size=1 color=#5f5f5f face="sans-serif">To:      
 </font><font size=1 face="sans-serif">openstack-dev@lists.openstack.org</font>
<br><font size=1 color=#5f5f5f face="sans-serif">Date:      
 </font><font size=1 face="sans-serif">04/03/2014 10:13 PM</font>
<br><font size=1 color=#5f5f5f face="sans-serif">Subject:    
   </font><font size=1 face="sans-serif">Re: [openstack-dev]
[heat] Problems with software config and Heat standalone configurations</font>
<br>
<hr noshade>
<br>
<br>
<br><font size=3>On 04/04/14 14:26, Michael Elder wrote:</font>
<br><font size=2 face="Arial">Hello,</font><font size=3> <br>
</font><font size=2 face="Arial"><br>
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. </font><font size=3><br>
</font><font size=2 face="Arial"><br>
The change was introduced in:</font><font size=3> <br>
</font><font size=2 face="Arial"><br>
commit 21f60b155e4b65396ebf77e05a0ef300e7c3c1cf</font><font size=3> </font><font size=2 face="Arial"><br>
Author: Steve Baker </font><a href=mailto:sbaker@redhat.com><font size=2 color=blue face="Arial"><u><sbaker@redhat.com></u></font></a><font size=3>
</font><font size=2 face="Arial"><br>
Change: </font><a href=https://review.openstack.org/#/c/67621/><font size=2 color=blue face="Arial"><u>https://review.openstack.org/#/c/67621/</u></font></a><font size=3>
<br>
</font><font size=2 face="Arial"><br>
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:</font><font size=3> <br>
</font><font size=2 face="Arial"><br>
    def <b>handle_create</b>(<i>self</i>):</font><font size=3>
</font><font size=2 face="Arial"><br>
        props = dict(<i>self</i>.properties)</font><font size=3>
</font><font size=2 face="Arial"><br>
        props[<i>self</i>.NAME] = <i>self</i>.physical_resource_name()</font><font size=3>
<br>
</font><font size=2 face="Arial"><br>
        sc = <i>self</i>.heat().software_configs.create(**props)
## HERE THE HEAT CLIENT IS CREATING A NEW SOFTWARE_CONFIG TO MAKE EACH
ONE IMMUTABLE</font><font size=3> </font><font size=2 face="Arial"><br>
        <i>self</i>.resource_id_set(sc.id)</font><font size=3>
<br>
</font><font size=2 face="Arial"><br>
My concerns with this approach:</font><font size=3> <br>
</font><font size=2 face="Arial"><br>
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, ..):</font><font size=3>
<br>
</font><font size=2 face="Arial"><br>
curl -i -X POST -H 'X-Auth-Key: password' -H 'Accept: application/json'
-H 'Content-Type: application/json' -H 'X-Auth-Url: </font><a href=http://10.10.0.101:5000/v2.0%27><font size=2 color=blue face="Arial"><u>http://[host]:5000/v2.0'</u></font></a><font size=2 face="Arial">
-H 'X-Auth-User: admin' -H 'User-Agent: python-heatclient' -d '{...}' </font><a href=http://10.0.2.15:8004/v1/><font size=2 color=blue face="Arial"><u>http://10.0.2.15:8004/v1/</u></font></a><font size=2 face="Arial">{tenant_id}</font><font size=3>
<br>
</font><font size=2 face="Arial"><br>
In this mode, the heat config file indicates standalone mode and can also
indicate multicloud support:</font><font size=3> <br>
</font><font size=2 face="Arial"><br>
# /etc/heat/heat.conf</font><font size=3> </font><font size=2 face="Arial"><br>
[paste_deploy]</font><font size=3> </font><font size=2 face="Arial"><br>
flavor = standalone</font><font size=3> <br>
</font><font size=2 face="Arial"><br>
[auth_password]</font><font size=3> </font><font size=2 face="Arial"><br>
allowed_auth_uris = http://[host1]:5000/v2.0,http://[host2]:5000/v2.0</font><font size=3>
</font><font size=2 face="Arial"><br>
multi_cloud = true</font><font size=3> <br>
</font><font size=2 face="Arial"><br>
Any keystone URL which is referenced is unaware of the orchestration engine
which is interacting with it. Herein lies the design flaw.</font><font size=3>
</font>
<br><font size=3>Its not so much a design flaw, its a bug where a new piece
of code interacts poorly with a mode that currently has few users and no
integration test coverage.<br>
</font>
<br><font size=2 face="Arial"><br>
When software_config calls self.heat(), it resolves clients.py's heat client:</font><font size=3>
<br>
</font><font size=2 face="Arial"><br>
    def <b>heat</b>(<i>self</i>):</font><font size=3> </font><font size=2 face="Arial"><br>
        if <i>self</i>._heat:</font><font size=3> </font><font size=2 face="Arial"><br>
            return <i>self</i>._heat</font><font size=3>
</font><font size=2 face="Arial"><br>
        <br>
        con = <i>self</i>.context</font><font size=3>
</font><font size=2 face="Arial"><br>
        if <i>self</i>.auth_token is None:</font><font size=3>
</font><font size=2 face="Arial"><br>
            logger.error(_(<i>"Heat
connection failed, no auth_token!"</i>))</font><font size=3> </font><font size=2 face="Arial"><br>
            return None</font><font size=3>
</font><font size=2 face="Arial"><br>
        # try the token</font><font size=3> </font><font size=2 face="Arial"><br>
        args = {</font><font size=3> </font><font size=2 face="Arial"><br>
                <i>'auth_url'</i>:
con.auth_url,</font><font size=3> </font><font size=2 face="Arial"><br>
                <i>'token'</i>:
<i>self</i>.auth_token,</font><font size=3> </font><font size=2 face="Arial"><br>
                <i>'<u>username</u>'</i>:
None,</font><font size=3> </font><font size=2 face="Arial"><br>
                <i>'password'</i>:
None,</font><font size=3> </font><font size=2 face="Arial"><br>
                <i>'ca_file'</i>:
<i>self</i>._get_client_option(<i>'heat'</i>, <i>'ca_file'</i>),</font><font size=3>
</font><font size=2 face="Arial"><br>
                <i>'cert_file'</i>:
<i>self</i>._get_client_option(<i>'heat'</i>, <i>'cert_file'</i>),</font><font size=3>
</font><font size=2 face="Arial"><br>
                <i>'key_file'</i>:
<i>self</i>._get_client_option(<i>'heat'</i>, <i>'key_file'</i>),</font><font size=3>
</font><font size=2 face="Arial"><br>
                <i>'insecure'</i>:
<i>self</i>._get_client_option(<i>'heat'</i>, <i>'insecure'</i>)  
<br>
         }</font><font size=3> <br>
</font><font size=2 face="Arial"><br>
        endpoint_type = <i>self</i>._get_client_option(<i>'heat'</i>,
<i>'endpoint_type'</i>)</font><font size=3> </font><font size=2 face="Arial"><br>
        endpoint = <i>self</i>._get_heat_url()</font><font size=3>
</font><font size=2 face="Arial"><br>
        if not endpoint:</font><font size=3> </font><font size=2 face="Arial"><br>
            endpoint = <i>self</i>.url_for(service_type=<i>'<u>orchestration</u>'</i>,</font><font size=3>
</font><font size=2 face="Arial"><br>
                    
               endpoint_type=endpoint_type)</font><font size=3>
</font><font size=2 face="Arial"><br>
        <i>self</i>._heat = heatclient.Client(<i>'1'</i>,
endpoint, **args)</font><font size=3> <br>
</font><font size=2 face="Arial"><br>
        return <i>self</i>._heat</font><font size=3>
<br>
</font><font size=2 face="Arial"><br>
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. </font><font size=3><br>
</font>
<br><font size=3>If you look at self._get_heat_url() you'll see that the
heat.conf [clients_heat] url will be used for the heat endpoint if it is
set. I would recommend setting that for standalone mode. A devstack change
for HEAT_STANDALONE would be helpful here.<br>
</font>
<br><font size=2 face="Arial">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. </font><font size=3><br>
</font><font size=2 face="Arial"><br>
One workaround that I've implemented locally is to change the logic to
check for standalone mode and send the username and password. </font><font size=3><br>
</font><font size=2 face="Arial"><br>
       flavor = <i>'default'</i></font><font size=3> </font><font size=2 face="Arial"><br>
        try:</font><font size=3> </font><font size=2 face="Arial"><br>
            logger.info(<i>"Configuration
is %s"</i> % str(cfg.CONF))</font><font size=3> </font><font size=2 face="Arial"><br>
            flavor = cfg.CONF.paste_deploy.flavor</font><font size=3>
</font><font size=2 face="Arial"><br>
        except cfg.NoSuchOptError as <u>nsoe</u>:</font><font size=3>
</font><font size=2 face="Arial"><br>
            flavor = <i>'default'</i></font><font size=3>
</font><font size=2 face="Arial"><br>
        logger.info(<i>"Flavor is %s"</i>
% flavor)</font><font size=3> </font><font size=2 face="Arial"><br>
        <br>
        # We really should examine the pipeline to
determine whether we're using <u>authtoken</u> or <u>authpassword</u>.</font><font size=3>
</font><font size=2 face="Arial"><br>
        if flavor == <i>'<u>standalone</u>'</i>:</font><font size=3>
</font><font size=2 face="Arial"><br>
            <br>
            context_map = <i>self</i>.context.to_dict()</font><font size=3>
</font><font size=2 face="Arial"><br>
            <br>
            if <i>'<u>username</u>'</i> in
context_map.keys():</font><font size=3> </font><font size=2 face="Arial"><br>
                username = context_map[<i>'<u>username</u>'</i>]</font><font size=3>
</font><font size=2 face="Arial"><br>
            else:</font><font size=3> </font><font size=2 face="Arial"><br>
                username = None</font><font size=3>
</font><font size=2 face="Arial"><br>
    <br>
            if <i>'password'</i> in context_map.keys():</font><font size=3>
</font><font size=2 face="Arial"><br>
                password = context_map[<i>'password'</i>]</font><font size=3>
</font><font size=2 face="Arial"><br>
            else:</font><font size=3> </font><font size=2 face="Arial"><br>
                password = None</font><font size=3>
</font><font size=2 face="Arial"><br>
            <br>
            logger.info(<i>"Configuring
<u>username</u>='%s' and password='%s'"</i> % (username, password))</font><font size=3>
</font><font size=2 face="Arial"><br>
            args = {</font><font size=3>
</font><font size=2 face="Arial"><br>
                <i>'auth_url'</i>:
con.auth_url,</font><font size=3> </font><font size=2 face="Arial"><br>
                <i>'token'</i>:
None,</font><font size=3> </font><font size=2 face="Arial"><br>
                <i>'<u>username</u>'</i>:
username,</font><font size=3> </font><font size=2 face="Arial"><br>
                <i>'password'</i>:
password,</font><font size=3> </font><font size=2 face="Arial"><br>
                <i>'ca_file'</i>:
<i>self</i>._get_client_option(<i>'heat'</i>, <i>'ca_file'</i>),</font><font size=3>
</font><font size=2 face="Arial"><br>
                <i>'cert_file'</i>:
<i>self</i>._get_client_option(<i>'heat'</i>, <i>'cert_file'</i>),</font><font size=3>
</font><font size=2 face="Arial"><br>
                <i>'key_file'</i>:
<i>self</i>._get_client_option(<i>'heat'</i>, <i>'key_file'</i>),</font><font size=3>
</font><font size=2 face="Arial"><br>
                <i>'insecure'</i>:
<i>self</i>._get_client_option(<i>'heat'</i>, <i>'insecure'</i>)</font><font size=3>
</font><font size=2 face="Arial"><br>
            }  </font><font size=3>
</font><font size=2 face="Arial"><br>
        else:</font><font size=3> </font><font size=2 face="Arial"><br>
            if <i>self</i>.auth_token is
None:</font><font size=3> </font><font size=2 face="Arial"><br>
                logger.error(_(<i>"Heat
connection failed, no auth_token!"</i>))</font><font size=3> </font><font size=2 face="Arial"><br>
                return None</font><font size=3>
</font><font size=2 face="Arial"><br>
...</font><font size=3> <br>
</font><font size=2 face="Arial"><br>
Is this a known issue? </font>
<br><font size=3>This is a great summary of the problem, but it really
belongs in a launchpad bug. Lets discuss potential solutions there.<br>
</font><font size=3 color=blue><u><br>
</u></font><a href="https://bugs.launchpad.net/heat/+filebug"><font size=3 color=blue><u>https://bugs.launchpad.net/heat/+filebug</u></font></a><font size=3><br>
<br>
cheers</font><tt><font size=2>_______________________________________________<br>
OpenStack-dev mailing list<br>
OpenStack-dev@lists.openstack.org<br>
</font></tt><a href="http://lists.openstack.org/cgi-bin/mailman/listinfo/openstack-dev"><tt><font size=2>http://lists.openstack.org/cgi-bin/mailman/listinfo/openstack-dev</font></tt></a><tt><font size=2><br>
</font></tt>
<br>