<html>
  <head>
    <meta content="text/html; charset=ISO-8859-1"
      http-equiv="Content-Type">
  </head>
  <body bgcolor="#FFFFFF" text="#000000">
    <div class="moz-cite-prefix">On 04/04/14 14:26, Michael Elder wrote:<br>
    </div>
    <blockquote
cite="mid:OF0BB3C63D.E901237B-ON85257CB0.0005FFCF-85257CB0.0007E21D@us.ibm.com"
      type="cite"><font face="Arial" size="2">Hello,</font>
      <br>
      <br>
      <font face="Arial" size="2">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>
      <br>
      <br>
      <font face="Arial" size="2">The change was introduced in:</font>
      <br>
      <br>
      <font face="Arial" size="2">commit
        21f60b155e4b65396ebf77e05a0ef300e7c3c1cf</font>
      <br>
      <font face="Arial" size="2">Author: Steve Baker
        <a class="moz-txt-link-rfc2396E" href="mailto:sbaker@redhat.com"><sbaker@redhat.com></a></font>
      <br>
      <font face="Arial" size="2">Change: </font><a
        moz-do-not-send="true"
        href="https://review.openstack.org/#/c/67621/"><font
          face="Arial" size="2">https://review.openstack.org/#/c/67621/</font></a>
      <br>
      <br>
      <font face="Arial" size="2">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>
      <br>
      <br>
      <font face="Arial" size="2">    def <b>handle_create</b>(<i>self</i>):</font>
      <br>
      <font face="Arial" size="2">        props = dict(<i>self</i>.properties)</font>
      <br>
      <font face="Arial" size="2">        props[<i>self</i>.NAME]
        = <i>self</i>.physical_resource_name()</font>
      <br>
      <br>
      <font face="Arial" size="2">        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>
      <br>
      <font face="Arial" size="2">        <i>self</i>.resource_id_set(sc.id)</font>
      <br>
      <br>
      <font face="Arial" size="2">My concerns with this approach:</font>
      <br>
      <br>
      <font face="Arial" size="2">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>
      <br>
      <br>
      <font face="Arial" size="2">curl -i -X POST -H 'X-Auth-Key:
        password'
        -H 'Accept: application/json' -H 'Content-Type:
        application/json' -H 'X-Auth-Url:
      </font><a moz-do-not-send="true"
        href="http://10.10.0.101:5000/v2.0%27"><font face="Arial"
          size="2">http://[host]:5000/v2.0'</font></a><font face="Arial"
        size="2">
        -H 'X-Auth-User: admin' -H 'User-Agent: python-heatclient' -d
        '{...}' </font><a moz-do-not-send="true"
        href="http://10.0.2.15:8004/v1/"><font face="Arial" size="2">http://10.0.2.15:8004/v1/</font></a><font
        face="Arial" size="2">{tenant_id}</font>
      <br>
      <br>
      <font face="Arial" size="2">In this mode, the heat config file
        indicates
        standalone mode and can also indicate multicloud support:</font>
      <br>
      <br>
      <font face="Arial" size="2"># /etc/heat/heat.conf</font>
      <br>
      <font face="Arial" size="2">[paste_deploy]</font>
      <br>
      <font face="Arial" size="2">flavor = standalone</font>
      <br>
      <br>
      <font face="Arial" size="2">[auth_password]</font>
      <br>
      <font face="Arial" size="2">allowed_auth_uris =
        http://[host1]:5000/v2.0,http://[host2]:5000/v2.0</font>
      <br>
      <font face="Arial" size="2">multi_cloud = true</font>
      <br>
      <br>
      <font face="Arial" size="2">Any keystone URL which is referenced
        is unaware
        of the orchestration engine which is interacting with it. Herein
        lies the
        design flaw.</font>
      <br>
    </blockquote>
    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>
    <br>
    <blockquote
cite="mid:OF0BB3C63D.E901237B-ON85257CB0.0005FFCF-85257CB0.0007E21D@us.ibm.com"
      type="cite">
      <br>
      <font face="Arial" size="2">When software_config calls
        self.heat(), it
        resolves clients.py's heat client:</font>
      <br>
      <br>
      <font face="Arial" size="2">    def <b>heat</b>(<i>self</i>):</font>
      <br>
      <font face="Arial" size="2">        if <i>self</i>._heat:</font>
      <br>
      <font face="Arial" size="2">           
        return <i>self</i>._heat</font>
      <br>
      <font face="Arial" size="2">        </font>
      <br>
      <font face="Arial" size="2">        con = <i>self</i>.context</font>
      <br>
      <font face="Arial" size="2">        if <i>self</i>.auth_token
        is None:</font>
      <br>
      <font face="Arial" size="2">           
        logger.error(_(<i>"Heat connection failed, no auth_token!"</i>))</font>
      <br>
      <font face="Arial" size="2">           
        return None</font>
      <br>
      <font face="Arial" size="2">        # try the token</font>
      <br>
      <font face="Arial" size="2">        args = {</font>
      <br>
      <font face="Arial" size="2">           
            <i>'auth_url'</i>: con.auth_url,</font>
      <br>
      <font face="Arial" size="2">           
            <i>'token'</i>: <i>self</i>.auth_token,</font>
      <br>
      <font face="Arial" size="2">           
            <i>'<u>username</u>'</i>: None,</font>
      <br>
      <font face="Arial" size="2">           
            <i>'password'</i>: None,</font>
      <br>
      <font face="Arial" size="2">           
            <i>'ca_file'</i>: <i>self</i>._get_client_option(<i>'heat'</i>,
        <i>'ca_file'</i>),</font>
      <br>
      <font face="Arial" size="2">           
            <i>'cert_file'</i>: <i>self</i>._get_client_option(<i>'heat'</i>,
        <i>'cert_file'</i>),</font>
      <br>
      <font face="Arial" size="2">           
            <i>'key_file'</i>: <i>self</i>._get_client_option(<i>'heat'</i>,
        <i>'key_file'</i>),</font>
      <br>
      <font face="Arial" size="2">           
            <i>'insecure'</i>: <i>self</i>._get_client_option(<i>'heat'</i>,
        <i>'insecure'</i>)   </font>
      <br>
      <font face="Arial" size="2">         }</font>
      <br>
      <br>
      <font face="Arial" size="2">        endpoint_type
        = <i>self</i>._get_client_option(<i>'heat'</i>, <i>'endpoint_type'</i>)</font>
      <br>
      <font face="Arial" size="2">        endpoint = <i>self</i>._get_heat_url()</font>
      <br>
      <font face="Arial" size="2">        if not endpoint:</font>
      <br>
      <font face="Arial" size="2">           
        endpoint = <i>self</i>.url_for(service_type=<i>'<u>orchestration</u>'</i>,</font>
      <br>
      <font face="Arial" size="2">           
                             
          endpoint_type=endpoint_type)</font>
      <br>
      <font face="Arial" size="2">        <i>self</i>._heat
        = heatclient.Client(<i>'1'</i>, endpoint, **args)</font>
      <br>
      <br>
      <font face="Arial" size="2">        return <i>self</i>._heat</font>
      <br>
      <br>
      <font face="Arial" size="2">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>
      <br>
      <br>
    </blockquote>
    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>
    <br>
    <blockquote
cite="mid:OF0BB3C63D.E901237B-ON85257CB0.0005FFCF-85257CB0.0007E21D@us.ibm.com"
      type="cite"><font face="Arial" size="2">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>
      <br>
      <br>
      <font face="Arial" size="2">One workaround that I've implemented
        locally
        is to change the logic to check for standalone mode and send the
        username
        and password. </font>
      <br>
      <br>
      <font face="Arial" size="2">       flavor = <i>'default'</i></font>
      <br>
      <font face="Arial" size="2">        try:</font>
      <br>
      <font face="Arial" size="2">           
        logger.info(<i>"Configuration is %s"</i> % str(cfg.CONF))</font>
      <br>
      <font face="Arial" size="2">           
        flavor = cfg.CONF.paste_deploy.flavor</font>
      <br>
      <font face="Arial" size="2">        except cfg.NoSuchOptError
        as <u>nsoe</u>:</font>
      <br>
      <font face="Arial" size="2">           
        flavor = <i>'default'</i></font>
      <br>
      <font face="Arial" size="2">        logger.info(<i>"Flavor
          is %s"</i> % flavor)</font>
      <br>
      <font face="Arial" size="2">        </font>
      <br>
      <font face="Arial" size="2">        # We really should
        examine the pipeline to determine whether we're using <u>authtoken</u>
        or <u>authpassword</u>.</font>
      <br>
      <font face="Arial" size="2">        if flavor ==
        <i>'<u>standalone</u>'</i>:</font>
      <br>
      <font face="Arial" size="2">           
      </font>
      <br>
      <font face="Arial" size="2">           
        context_map = <i>self</i>.context.to_dict()</font>
      <br>
      <font face="Arial" size="2">           
      </font>
      <br>
      <font face="Arial" size="2">           
        if <i>'<u>username</u>'</i> in context_map.keys():</font>
      <br>
      <font face="Arial" size="2">           
            username = context_map[<i>'<u>username</u>'</i>]</font>
      <br>
      <font face="Arial" size="2">           
        else:</font>
      <br>
      <font face="Arial" size="2">           
            username = None</font>
      <br>
      <font face="Arial" size="2">    </font>
      <br>
      <font face="Arial" size="2">           
        if <i>'password'</i> in context_map.keys():</font>
      <br>
      <font face="Arial" size="2">           
            password = context_map[<i>'password'</i>]</font>
      <br>
      <font face="Arial" size="2">           
        else:</font>
      <br>
      <font face="Arial" size="2">           
            password = None</font>
      <br>
      <font face="Arial" size="2">           
      </font>
      <br>
      <font face="Arial" size="2">           
        logger.info(<i>"Configuring <u>username</u>='%s' and
          password='%s'"</i>
        % (username, password))</font>
      <br>
      <font face="Arial" size="2">           
        args = {</font>
      <br>
      <font face="Arial" size="2">           
            <i>'auth_url'</i>: con.auth_url,</font>
      <br>
      <font face="Arial" size="2">           
            <i>'token'</i>: None,</font>
      <br>
      <font face="Arial" size="2">           
            <i>'<u>username</u>'</i>: username,</font>
      <br>
      <font face="Arial" size="2">           
            <i>'password'</i>: password,</font>
      <br>
      <font face="Arial" size="2">           
            <i>'ca_file'</i>: <i>self</i>._get_client_option(<i>'heat'</i>,
        <i>'ca_file'</i>),</font>
      <br>
      <font face="Arial" size="2">           
            <i>'cert_file'</i>: <i>self</i>._get_client_option(<i>'heat'</i>,
        <i>'cert_file'</i>),</font>
      <br>
      <font face="Arial" size="2">           
            <i>'key_file'</i>: <i>self</i>._get_client_option(<i>'heat'</i>,
        <i>'key_file'</i>),</font>
      <br>
      <font face="Arial" size="2">           
            <i>'insecure'</i>: <i>self</i>._get_client_option(<i>'heat'</i>,
        <i>'insecure'</i>)</font>
      <br>
      <font face="Arial" size="2">           
        }  </font>
      <br>
      <font face="Arial" size="2">        else:</font>
      <br>
      <font face="Arial" size="2">           
        if <i>self</i>.auth_token is None:</font>
      <br>
      <font face="Arial" size="2">           
            logger.error(_(<i>"Heat connection failed, no auth_token!"</i>))</font>
      <br>
      <font face="Arial" size="2">           
            return None</font>
      <br>
      <font face="Arial" size="2">...</font>
      <br>
      <br>
      <font face="Arial" size="2">Is this a known issue? </font>
      <br>
    </blockquote>
    This is a great summary of the problem, but it really belongs in a
    launchpad bug. Lets discuss potential solutions there.<br>
    <br>
    <a class="moz-txt-link-freetext" href="https://bugs.launchpad.net/heat/+filebug">https://bugs.launchpad.net/heat/+filebug</a><br>
    <br>
    cheers<br>
  </body>
</html>