【问题标题】:Ansible **ERROR! Unexpected Exception: unhashable type: 'dict'** issueAnsible **错误!意外异常:不可散列类型:\'dict\'** 问题
【发布时间】:2022-10-25 19:01:54
【问题描述】:

我有一个 Ansible 剧本,可以在我的角色中调用许多“函数”,每个函数根据过去的命令行/剧本选项运行不同的任务,其中两个由不同的调用组成,以获取有关单个 MQ 通道或多个通道的信息。

如果需要单个通道详细信息,则调用子函数

功能1

- include: subFunction1 CHANNEL_NAME={{CHANNELNAME}}..... where CHANNELNAME is a past value

多个通道调用相同的子函数:

功能2

- 'command to get a List Of Channels'
   register: CHANNEL_LIST
- include: subfunction1 CHANNEL_NAME={{item}}
  with_items: "{{CHANNEL_LIST.stdout_lines}}"

然后子函数继续获取有关通道的信息,在每个通道上使用 MQ 命令并输出状态和信息,包括所有通道是否处于以下状态之一,已停止、运行或混合(非活动,开始,停止),这些细节从任务注册值 stdout_lines 添加到嵌套变量中:

CHSstatus: 
  - CHANNEL: "[CHANNEL_NAME]"
    STATUS:  "[STATUS]"

如果找不到通道状态,则通道未定义或通道已定义但没有状态(一个 MQ 功能,其中通道的状态可以是多个之一,但如果它实际上是 INACTIVE 则不返回任何信息),在定义了 Channel 但没有状态 (INACTIVE) 的情况下,会创建一个虚拟嵌套变量:

CHSstatus: 
  - CHANNEL: "{{CHANNEL_NAME}}"
    STATUS:  "Unknown STATUS"
    

这两个函数都可以工作到这一点,但是当尝试将此虚拟值用于 Function2 时
我收到此嵌套变量的以下错误:

错误!意外异常:不可散列类型:'dict'

我能看到的唯一区别是对于 Function1,过去的 CHANNEL_NAME 是 AnsibleUnicode 类型,但是对于 Function2,过去的每个“项目”值都是 AnsibleUnsafeText 类型

有人对如何解决这个问题有任何建议吗?

感谢大家

调查进一步表明,错误发生在任务的后期,而不是它报告的行。 似乎这个问题已被标记为没有帮助或不清楚,并且没有进行任何研究。情况并非如此,因为我已经在这几天了,但是我似乎确实取得了一些进展

为了更清楚一点,我得到的基本上是两种运行代码的方法,方法或 Function1 如上所述

函数1.yml

include: subFunction1.yml CHANNEL_NAME={{CHANNELNAME}}

函数2.yml

# MQ command to get a list of Defined channels
shell: # runmqsc command on QMGR for CHANNEL_NAME
register: CHANNEL_LIST
include: subfunction1.yml CHANNEL_NAME={{item}}
with_items: "{{CHANNEL_LIST.stdout_lines}}

包含文件相当长,但基本上执行以下操作

子功能1 .yml

# check if the CHANNEL_NAME exists
# reports if channel does not exist
# get the status of the channel if it does
# parses the result of the status to a variable
CHLstatus: "{{CHLstatus + [result_dict]}}"
with_items: "{{above.result.stdout_lines}}"
vars:
  result_dict: #parsed out from the stdout_lines
# if there is no output from above status call then a dummy variable is created
  CHSstatus: 
  - CHANNEL: "{{CHANNEL_NAME}}"
    STATUS:  "Unknown STATUS"

至此,我已经输出了结果,可以看到一切正常。 下一步是确定当有多个 Channel 时,有多少 Channel 处于 RUNNING、STOPPED 或 OTHER 状态,从而发生错误。 工作正常时,变量类型是

CHANNEL_NAME      = AnsibleUnicode
CHSstatus         = list
CHSstatus.STATUS  = unicode
CHSstatus.CHANNEL = unicode

失败时我们得到

CHANNEL_NAME      = AnsibleUnsafeText
CHSstatus         = list
CHSstatus.STATUS  = unicode
CHSstatus.CHANNEL = unicode

所以看起来 DUMMY CHSstatus 的创建确实是问题所在 我什至硬编码了 CHANNEL_NAME 的值,但仍然没有解决它

正确值

CHSstatus = [{'STATUS': u'RUNNING', 'CHANNEL': u'TO_LOCAL'}]"

破碎值

CHSstatus = [{u'STATUS': u'Unknown STATUS', u'CHANNEL': u'DUMMY NOT DEFINED'}]

损坏的位中有一个额外的“u”,但我不知道如何摆脱它

【问题讨论】:

  • 这是很多话,很少代码;请阅读MCVE 并考虑“最小”部分。它可以帮助您在制作本地可重现的案例时进行自我调试,并帮助为您提供免费咨询的人不必在午餐时阅读战争与和平。祝你好运
  • 我可以理解您所说的代码很少,但由于实际代码分为几个任务文件,总共 6 个,我试图只提供相关的 sn-ps。基本上,错误仅在这些文件中的一个中,这些文件为过去包含的文件的每个 MQ 通道调用,我遇到的问题是,当我将 CHANNEL_NAME 作为字符串传递时它工作正常,但是当我通过通道列表时使用对 MQ 命令的调用的输出,注册的 stdout_lines 中的值不是字符串
  • 对同一个 subfunction1 有两个不同的调用包括: subfunction1 CHANNEL_NAME="CHANNEL_A" 和 include: subfunction1 CHANNEL_NAME="{{item}}" with_items: "{{ListOfChennels.stdout_lines}}" 有没有办法确保没有传递列表项并将其转换为字符串?我认为第一个作为字符串“CHANNEL_A”传递,而列表作为“CHANNEL_n”元素的“字典”传递。希望能更好地解释我将不得不重写我拥有的代码,因为这是我无法真正分享的生产代码

标签: ansible ibm-mq


【解决方案1】:

不是一个真正的答案,因为我仍然有同样的问题,但是需要添加太多细节才能添加到评论中,不确定我的代码中是否存在一些错误。 这显示了一个带有最少代码的新剧本,以尝试查看正在发生的事情,虽然代码基本相同,但现在不会失败,我正在使用原始剧本中的角色,也许我应该在下面扩展以查看是否可以让它失败

新剧本

  - name: Testing
    hosts: localhost
    strategy: debug
    vars:
      Channel_A:  "CHANNELA"
      chl_exists: false
      chs_exists: false
    tasks:

功能一

  - set_fact:
      CHSstatus:  []
      allStopped: []
      allRunning: []
      mixedState: []
  # This is the result of an MQ Command line to get all the required CHANNEL name(s) we need the status of
  - shell: echo "CLUSQMGR(REMOTQMGR) CHANNEL(CHANNEL1)"|grep CHANNEL| cut -d'(' -f3 | cut -d')' -f1
    register: channelNames
  # At this stage we would loop through each output and call the subFunction
  - include: chlStatus.yml CHANNEL_NAME={{item}} 
    with_items: "{{channelNames.stdout_lines}}"       # past CHANNEL_NAME is [u'CHANNEL1']

功能二

  - set_fact:
      CHSstatus:  []
      allStopped: []
      allRunning: []
      mixedState: []
  - include: chlStatus.yml CHANNEL_NAME={{Channel_A}}   

包含文件非常复杂,无论如何对我来说都是如此;

chlStatus.yml

 - block:
        # this is a simulated output of the command to get the Status of a Channel
        - shell: echo "  CHANNEL({{CHANNEL_NAME}}) STATUS(RUNNING)" |sed 's/^[^  ].*$/%/g' | tr -s " " | tr -d "
" | tr "%" "
"|grep CHANNEL|sed 's/ CURRENT//g' | sed 's/^ //g'|sed 's/ *$//g'
          register:
            listOfChannels    
        - name: Set CHS status
          set_fact:
            CHSstatus: "{{CHSstatus + [result_dict]}}"              
          with_items:  "{{listOfChannels.stdout_lines}}"            # [u'CHANNEL(CHANNEL1) STATUS(RUNNING)']
          loop_control:
            loop_var:   loopChannelExists
          vars:
            replace_items: "{{ loopChannelExists|replace('( )','(_)')|replace('(','&')|replace(') ','%')|replace(' ','_')|replace('&','(')|replace('%',') ')}}"
            mapped_line: "{{ replace_items.split()|
                        map('regex_replace', '\((.+)\)$', ' \1')|
                        list }}"
            split_line: |
              {% for i in mapped_line %}
              {% set arr = i.split() %}
              {{ arr.0 }}: '{{ arr.1}}'
              {% endfor %}
            result_dict: "{{ split_line|from_yaml }}"
        - debug:
            msg:
              - "Working {{CHSstatus}}"                             # [{'STATUS': u'RUNNING', 'CHANNEL': u'CHANNEL1'}]
# At this stage we can see that the simulated result of the channel status is found, however we want to assume that this 
# has not found a status. We are going to create a dummy result anyway

  - name: If no channel status 
    set_fact:
      CHSstatus: "{{[result_dict]}}"
    vars:
      CHANNEL_VAR: "{%if (chl_exists)%}{{CHANNEL_NAME}}_DEFINED {%else%}{{CHANNEL_NAME}}_NOT_DEFINED{%endif%}"
      STATUS_VAR:  "{%if (chl_exists)%}INACTIVE{%else%}UNKNOWN{%endif%}"
      DUMMY_VAR:   "CHANNEL({{CHANNEL_VAR}}) STATUS({{STATUS_VAR}})" 
      replace_items: "{{ DUMMY_VAR|replace('( )','(_)')|replace('(','&')|replace(') ','%')|replace(' ','_')|replace('&','(')|replace('%',') ')}}"
      mapped_line: "{{ replace_items.split()|
                  map('regex_replace', '\((.+)\)$', ' \1')|
                  list }}"
      split_line: |
        {% for i in mapped_line %}
        {% set arr = i.split() %}
        {{ arr.0 }}: {{ arr.1|default('NA') }}
        {% endfor %}
      result_dict: "{{ split_line|from_yaml }}"
  - debug:
      msg:
        - "Dummy {{CHSstatus}}"                                   #  [{'STATUS': u'UNKNOWN', 'CHANNEL': u'CHANNEL1_NOT_DEFINED'}]
# The creation of the Dummy has worked and comparing the output of a valid call and the Dummy creation i cannot see any 
# difference between the two outputs
# Simulated found channel
#   [{'STATUS': u'RUNNING', 'CHANNEL': u'CHANNEL1'}]
# Dummy output 
#   [{'STATUS': u'UNKNOWN', 'CHANNEL': u'CHANNEL1_NOT_DEFINED'}]
# the next step is to get some details to see what the state of all the channel are which may be used in other calls
# In original code which these excerpts are taken from i now get an error at this point 
# ERROR! Unexpected Exception: unhashable type: 'dict'
# to see the full traceback, use -vvv
# This fails when trying at access the dummy channel status but only when looping through a list of channels

  - set_fact:
      allStopped: "{%if splitStatus.STATUS == 'STOPPED'%}{{allStopped + [splitStatus.CHANNEL]}}{%else%}{{allStopped}}{%endif%}"
      allRunning: "{%if splitStatus.STATUS == 'RUNNING'%}{{allRunning + [splitStatus.CHANNEL]}}{%else%}{{allRunning}}{%endif%}"
      mixedState: "{%if splitStatus.STATUS != 'STOPPED' and splitStatus.STATUS != 'RUNNING'%}{{mixedState + [splitStatus.CHANNEL]}}{%else%}{{mixedState}}{%endif%}"
    with_items: "{{CHSstatus}}"
    loop_control:
      loop_var:   splitStatus
  - name: RESULT
    set_fact:
      isAllStopped: "{{ 'true' if CHSstatus|length == allStopped|length else 'false' }}"
      isAllRunning: "{{ 'true' if CHSstatus|length == allRunning|length else 'false' }}"

所以代码在这里

【讨论】:

    猜你喜欢
    • 2015-11-24
    • 1970-01-01
    • 1970-01-01
    • 2021-01-10
    • 2021-12-22
    • 1970-01-01
    • 1970-01-01
    • 2012-10-27
    • 1970-01-01
    相关资源
    最近更新 更多