Ошибка Ansible 'NoneType' object is not iterable" при выполнении json_query

У меня есть следующий код в моем Ansible 2.9, чтобы в основном отображать вывод другой задачи ansible, которая создает виртуальные машины, и упорядочивать этот вывод в удобочитаемом формате:

- name: VM creation ouput
  debug:
    msg: "{{ result.stdout | from_json | json_query(jmesquery)  | sort(attribute='VM') }}"
  vars:
    jmesquery: "[].{VM: ResultName, CreatedSuccessfully: ErrorInfo.IsSuccess, PercentCompleted: Progress, CreationTimeCompleted: ReadableEndTime.DateTime}"

Это отлично работает, если я просто создаю более 1 (например, 2) виртуальных машин. Однако, когда я создаю только 1 виртуальную машину, ansible завершается со следующей ошибкой:

fatal: [localhost]: FAILED! => {
    "msg": "Unexpected templating type error occurred on ({{ result.stdout | from_json | json_query(jmesquery) | sort(attribute='VM') }}): 'NoneType' object is not iterable"
}

Может ли кто-нибудь пролить свет на то, почему json_query будет работать с выходом более чем двух виртуальных машин, а не только с одной? И что можно изменить в коде выше, чтобы он работал в обоих случаях?

Обновление (спасибо за подсказку!), вот стандартный вывод (определяется как result.stdout):

    "stdout": {
        "ErrorInfo": {
            "CSMMessageString": "Error Code : Success ; Message :  ; Recommended Action : ",
            "CloudProblem": "",
            "Code": 0,
            "DetailedCode": 0,
            "DetailedErrorCode": "",
            "DetailedSource": 0,
            "DisplayableErrorCode": 0,
            "ErrorCodeString": "0",
            "ErrorType": 0,
            "Exception": null,
            "ExceptionDetails": "",
            "Formatter": {},
            "GetMessageFormatterHandler": null,
            "IsConditionallyTerminating": false,
            "IsDeploymentBlocker": false,
            "IsMomAlert": false,
            "IsSuccess": true,
            "IsTerminating": false,
            "MessageParameters": {},
            "MomAlertSeverity": 0,
            "Problem": "",
            "RecommendedAction": "",
            "RecommendedActionCLI": "",
            "ShowDetailedError": false
        },
        "Progress": "100%",
        "ReadableEndTime": {
            "DateTime": "Monday, June 8, 2020 10:24:02 AM",
            "DisplayHint": 2,
            "value": "/Date(1591575842677)/"
        },
        "ResultName": "MyVM"
    }

Обновление: я попробовал предложение Владимира (большое спасибо) и изменил свой код, как показано ниже:

- name: VM creation details
  debug:
    msg: "{{ result.stdout | from_json | json_query(jmesquery) }}"
  vars:
    jmesquery: "{VM: ResultName,
                     CreatedSuccessfully: ErrorInfo.IsSuccess,
                     PercentCompleted: Progress,
                     CreationTimeCompleted: ReadableEndTime.DateTime}"
  when: stdout is mapping
  ignore_errors: true

- name: VM creation details
  debug:
    msg: "{{ result.stdout | from_json | json_query(jmesquery) }}"
  vars:
    jmesquery: "[].{VM: ResultName,
                        CreatedSuccessfully: ErrorInfo.IsSuccess,
                        PercentCompleted: Progress,
                        CreationTimeCompleted: ReadableEndTime.DateTime}"
  when: stdout is not mapping
  ignore_errors: true

Однако это не удается с ошибкой:

TASK [createvm : VM creation details] ***************************************************************************************************************************************************************************
task path: /test/server.yml:41
skipping: [myserver] => {}

TASK [createvm : VM creation details] ***************************************************************************************************************************************************************************
task path: /test/server.yml:52
fatal: [myserver]: FAILED! => {
    "msg": "the field 'args' has an invalid value ({u'msg': u'{{ result.stdout | from_json | json_query(jmesquery) }}'}), and could not be converted to an dict.The error was: No JSON object could be decoded\n\nThe error appears to be in '/test/server': line 52, column 3, but may\nbe elsewhere in the file depending on the exact syntax problem.\n\nThe offending line appears to be:\n\n\n- name: VM creation details\n  ^ here\n"
}
...ignoring

Любая идея, что еще я мог делать неправильно ..?

Спасибо! Дж


person JaneD    schedule 12.06.2020    source источник
comment
Обновите вопрос с помощью result.stdout. Сделайте его mcve.   -  person Vladimir Botka    schedule 12.06.2020


Ответы (2)


Используйте тестовое сопоставление, чтобы выбрать правильный запрос для словаря и списка. Например,

    - debug:
        msg: "{{ stdout|json_query(jmesquery) }}"
      vars:
        jmesquery: "{VM: ResultName,
                     CreatedSuccessfully: ErrorInfo.IsSuccess,
                     PercentCompleted: Progress,
                     CreationTimeCompleted: ReadableEndTime.DateTime}"
      when: stdout is mapping

    - debug:
        msg: "{{ stdout|json_query(jmesquery) }}"
      vars:
        jmesquery: "[].{VM: ResultName,
                        CreatedSuccessfully: ErrorInfo.IsSuccess,
                        PercentCompleted: Progress,
                        CreationTimeCompleted: ReadableEndTime.DateTime}"
      when: stdout is not mapping

Следующий вариант — использовать фильтр type_debug, который показывает тип переменной. Например, в этом случае

    - debug:
        msg: "{{ stdout|type_debug }}"

дает

    "msg": "dict"
person Vladimir Botka    schedule 13.06.2020
comment
Привет Владимир, большое спасибо за ваш вклад. Я попробовал ваше предложение, но столкнулся с другой ошибкой. Обновил свой вопрос этим. Ценим вашу помощь и время. - person JaneD; 14.06.2020
comment
Изучив это снова, я обнаружил, что стандартный вывод был изменен из-за некоторых изменений в модулях powershell, которые мы вызывали. Это исправлено, и теперь это работает :) Большое спасибо! - person JaneD; 17.06.2020

Вы получаете сообщение об ошибке, потому что передаете пустой результат фильтру sort, который ожидает список. Вы получаете пустой результат из выражения json_query, потому что вы начинаете с [], которое ссылается на список, а result.stdout — это словарь, а не список. Следующее дает действительный результат:

    - debug:
        msg: "{{ result.stdout | from_json | json_query(jmesquery) }}"
      vars:
        jmesquery: "{VM: ResultName, CreatedSuccessfully: ErrorInfo.IsSuccess, PercentCompleted: Progress, CreationTimeCompleted: ReadableEndTime.DateTime}"

Используя образцы данных, которые вы предоставили в своем вопросе, это дает:

TASK [debug] *********************************************************************************************************************************************************************************
ok: [localhost] => {
    "msg": {
        "CreatedSuccessfully": true,
        "CreationTimeCompleted": "Monday, June 8, 2020 10:24:02 AM",
        "PercentCompleted": "100%",
        "VM": "MyVM"
    }
}

Здесь нечего делать sort, потому что результатом является один элемент, а не список.

person larsks    schedule 13.06.2020
comment
Привет, Ларск, я попробовал это, но получил следующую фатальную ошибку: [localhost]: FAILED! =› { msg: поле 'args' имеет недопустимое значение ({u'msg': u'{{ result.stdout | from_json | json_query(jmesquery) }}'}) и не может быть преобразовано в dict. Ошибка: объект JSON не может быть декодирован\n` - person JaneD; 16.06.2020