在测试我自己的Ansible模块时,我遇到了这个特殊的错误:"setup error: No module named FabricVcon "
然而,当在Python中测试模块的基本API(也是自制的)时,代码可以无错误地工作。我很困惑,因为我用于其他基本API的Ansible Module模板是相同的,只是交换了相关信息。所有以前的类似模块都有效。为清楚起见,我开发的Ansible模块使用我开发的API Python文件。该Python API文件实现了官方支持的思科Python库。
编辑:部分问题出在错误代码中。 ucsmsdk基类是FabricVCon,而错误告诉我它找不到FabricVcon。区别在于名称中的第二个C.我在发布问题之前对代码进行了更改,以确保使用了FabricVCon,但错误仍然存在。
我目前正致力于使用Ansible通过Python中的ucsmsdk自动创建和修改服务配置文件模板。我一直在为自己的CiscoUcs团队的ucsm_apis和ucsm-ansible回购做出贡献,他们使用他们的文件作为我自己应该如何工作的指南。我安装了自己的repos中的文件,并且正常运行,除了这个。下面我已经在问题中添加了相关代码,但是如果您发现需要更多代码,请参阅GitHub account上的两个分析
---
- name: test the test the fabric_vcon_module
connection: local
hosts: localhost
tasks:
- name: Make the fabric vcon now
fabric_vcon_module:
id: "1"
ls_server_dn: "org-root/org-VM/ls-SCALEIO"
fabric: "NONE"
inst_type: "manual"
placement: "physical"
select: "all"
share: "shared"
transport: "ethernet, fc"
state: present
ucs_ip: "IP"
ucs_username: "USER"
ucs_password: "PWD"
(最后评论是我对Python代码本身的测试)
"""
This module intends on creating higher level api calls for establishing an
Fabric Vcon
"""
from ucsmsdk.ucsexception import UcsOperationError
def fabric_vcon_create(handle, id, ls_server_dn, fabric='NONE',
inst_type="manual", placement="physical", select="all",
share="shared", transport="ethernet", **kwargs):
"""
create fabric vcon
Args:
handle (UcsHandle)
id (string): '1' or '2' or '3' or '4'
ls_server_dn (string):
fabric (string): 'A' or 'B' or 'any' or 'NONE'
inst_type (string): 'auto' or 'manual' or 'policy'
placement (string): 'auto' or 'physical'
select (string): 'all' or 'assigned-only' or 'dynamic-only' or
'exclude-dynamic' or 'exclude-unassigned' or
'exclude-usnic' or 'unassigned-only' or 'usnic-only'
share (string): 'different-transport' or 'exclusive-only' or
'exclusive-preferred' or 'same-transport' or 'shared'
transport (string):
Returns:
FabricVCon: managed object
Raises:
UcsOperationError: if LsServer is not present
Example:
"""
from ucsmsdk.mometa.fabric.FabricVCon import FabricVCon
obj = handle.query_dn(ls_server_dn)
if not obj:
raise UcsOperationError("fabric_vcon_create", "LsServer '%s' does not \
exist" % ls_server_dn)
mo = FabricVCon(parent_mo_or_dn=obj, id=id, fabric=fabric,
inst_type=inst_type, placement=placement, select=select,
share=share, transport=transport)
mo.set_prop_multiple(**kwargs)
handle.add_mo(mo, modify_present=True)
handle.commit()
return mo
def fabric_vcon_get(handle, id, ls_server_dn, caller="fabric_vcon_get"):
"""
get fabric vcon
Args:
handle (UcsHandle)
id (string):
ls_server_dn (string):
caller (string):
Returns:
FabricVCon: managed object
Raises:
UcsOperationError: if the FabricVCon is not present
Example:
"""
dn = ls_server_dn + "/vcon-" + id
mo = handle.query_dn(dn)
if mo is None:
raise UcsOperationError(caller, "FabricVCon '%s' does not exist" % dn)
return mo
def fabric_vcon_exists(handle, id, ls_server_dn, **kwargs):
"""
checks if fabric vcon exists
Args:
handle(UcsHandle)
id (string): ls server name
ls_server_dn (string): location to place ls server
**kwargs: key-value pair of managed object(MO) property and value, Use
'print(ucscoreutils.get_meta_info(<classid>).config_props)'
to get all configurable properties of class
Returns:
(True/False, FabricVCon mo/None)
Raises:
None
Example:
"""
try:
mo = fabric_vcon_get(handle=handle, id=id, ls_server_dn=ls_server_dn,
caller="fabric_vcon_exists")
except UcsOperationError:
return (False, None)
mo_exists = mo.check_prop_match(**kwargs)
return (mo_exists, mo if mo_exists else None)
def fabric_vcon_modify(handle, id, ls_server_dn, **kwargs):
"""
modifies fabric vcon
Args:
handle (UcsHandle)
id (string):
ls_server_dn (string):
**kwargs:
Returns:
FabricVCon: managed object
Raises:
UcsOperationError: if FabricVCon is not present
Example:
"""
mo = fabric_vcon_get(handle=handle, id=id, ls_server_dn=ls_server_dn,
caller="fabric_vcon_modify")
mo.set_prop_multiple(**kwargs)
handle.set_mo(mo)
handle.commit()
return mo
def fabric_vcon_delete(handle, id, ls_server_dn):
"""
deletes fabric vcon
Args:
handle (UcsHandle)
id (String): ls server name
ls_server_dn (string): ls server's full name
Returns:
None
Raises:
UcsOperationError: if FabricVCon is not present
Example:
"""
mo = fabric_vcon_get(handle=handle, id=id, ls_server_dn=ls_server_dn,
caller="fabric_vcon_delete")
handle.remove_mo()
handle.commit()
"""
if __name__ == "__main__":
from ucsmsdk.ucshandle import UcsHandle
handle = UcsHandle("10.94.254.136","ansible","elbisna1*")
handle.login()
fabric_vcon_create(handle, "4" ,"org-root/org-DHS-VM/ls-DS-ESX-C2-SCALEIO", fabric='NONE',
inst_type="manual", placement="physical", select="all",
share="shared", transport="ethernet")
print fabric_vcon_exists(handle, "4" ,"org-root/org-DHS-VM/ls-DS-ESX-C2-SCALEIO")
print fabric_vcon_get(handle, "4" ,"org-root/org-DHS-VM/ls-DS-ESX-C2-SCALEIO")
fabric_vcon_modify(handle, "4" ,"org-root/org-DHS-VM/ls-DS-ESX-C2-SCALEIO", inst_type="auto")
fabric_vcon_delete(handle, "4" ,"org-root/org-DHS-VM/ls-DS-ESX-C2-SCALEIO")
"""
#!/usr/bin/env python
from ansible.module_utils.basic import *
ANSIBLE_METADATA = {'metadata_version': '1.0',
'status': ['preview'],
'supported_by': 'community'}
DOCUMENTATION = '''
---
module: cisco_ucs_ls_server
short_description: configures ls server on a cisco ucs server profile
version_added: 0.9.0.0
description:
- configures ls server on a cisco ucs server profile
options:
state:
description:
- if C(present), will perform create/add/enable operation
- if C(absent), will perform delete/remove/disable operation
required: false
choices: ['present', 'absent']
default: "present"
id:
version_added: "1.0(1e)"
description: boot policy name
required: true
choices: ['1', '2', '3', '4']
ls_server_dn:
version_added: "1.0(1e)"
description:
required: false
fabric:
version_added: "1.0(1e)"
description:
required: false
choices: ['A', 'B', 'any', 'NONE']
inst_type:
version_added: "1.0(1e)"
description:
required: false
choices: ['auto', 'manual', 'policy']
placement:
version_added: "1.0(1e)"
description:
required: false
choices: ['auto', 'physical']
select:
version_added: "1.0(1e)"
description:
required: false
choices: ['all', 'assigned-only', 'dynamic-only', 'exclude-dynamic', 'exclude-unassigned',
'exclude-usnic', 'unassigned-only', 'usnic-only']
share:
version_added: "1.0(1e)"
description:
required: false
choices: ['different-transport', 'exclusive-only', 'exclusive-preferred', 'same-transport', 'shared']
transport:
version_added: "1.0(1e)"
description:
required: false
requirements: ['ucsmsdk', 'ucsm_apis']
author: "Cisco Systems Inc(ucs-python@cisco.com)"
'''
EXAMPLES = '''
- name:
fabric_vcon_module:
id: "1"
ls_server_dn: "org-root/ls-spt-test"
fabric: "B"
inst_type: "manual"
select: "assigned-only"
share: "different-transport"
state: "present"
ucs_ip: "192.168.1.1"
ucs_username: "admin"
ucs_password: "password"
'''
#Arguments object for the Managed Object in question
def _argument_mo():
return dict(
id=dict(required=True, type='str', choices=['1', '2', '3', '4']),
ls_server_dn=dict(required=True, type='str'),
fabric=dict(type='str', choices=['A', 'B', 'any', 'NONE'], default="NONE"),
inst_type=dict(type='str', choices=['auto', 'manual', 'policy'], default="manual"),
placement=dict(type='str', choices=['auto', 'physical'], default="physical"),
select=dict(type='str', choices=['all', 'assigned-only', 'dynamic-only', 'exclude-dynamic',
'exclude-unassigned', 'exclude-usnic', 'unassigned-only', 'usnic-only'],
default="all"),
share=dict(type='str', choices=['different-transport', 'exclusive-only',
'exclusive-preferred', 'same-transport', 'shared'], default="shared"),
transport=dict(type='str', default="ethernet")
)
#Arguments object unique to the Ansible Module
def _argument_custom():
return dict(
state=dict(default="present",
choices=['present', 'absent'],
type='str'),
)
#Arguments object related to the UcsHandle
def _argument_connection():
return dict(
# UcsHandle
ucs_server=dict(type='dict'),
# Ucs server credentials
ucs_ip=dict(type='str'),
ucs_username=dict(default="admin", type='str'),
ucs_password=dict(type='str', no_log=True),
ucs_port=dict(default=None),
ucs_secure=dict(default=None),
ucs_proxy=dict(default=None)
)
#Creates the AnsibleModule object with the all arguments
def _ansible_module_create():
argument_spec = dict()
argument_spec.update(_argument_connection())
argument_spec.update(_argument_mo())
argument_spec.update(_argument_custom())
return AnsibleModule(argument_spec,
supports_check_mode=True)
#Retrieves non-None mo properties
def _get_mo_params(params):
from ansible.module_utils.cisco_ucs import UcsConnection
args = {}
for key in _argument_mo():
if params.get(key) is None:
continue
args[key] = params.get(key)
return args
def setup_fabric_vcon(server, module):
from ucsm_apis.service_profile.fabric_vcon import fabric_vcon_create
from ucsm_apis.service_profile.fabric_vcon import fabric_vcon_exists
from ucsm_apis.service_profile.fabric_vcon import fabric_vcon_delete
ansible = module.params
args_mo = _get_mo_params(ansible)
exists, mo = fabric_vcon_exists(handle=server, **args_mo)
if ansible["state"] == "present":
if module.check_mode or exists:
return not exists
fabric_vcon_create(handle=server, **args_mo)
else:
if module.check_mode or not exists:
return exists
fabric_vcon_delete(server, mo.name, args_mo['org_dn'])
return True
#Attempts to run the above method and provides error handling if it fails
def setup(server, module):
result = {}
err = False
try:
result["changed"] = setup_fabric_vcon(server, module)
except Exception as e:
err = True
result["msg"] = "setup error: %s " % str(e)
result["changed"] = False
return result, err
#Creates the module and makes the connections, only real work is done in setup
def main():
from ansible.module_utils.cisco_ucs import UcsConnection
module = _ansible_module_create()
conn = UcsConnection(module)
server = conn.login()
result, err = setup(server, module)
conn.logout()
if err:
module.fail_json(**result)
module.exit_json(**result)
if __name__ == '__main__':
main()
答案 0 :(得分:0)
事实证明,Ansible正在/~/.local/lib/python2.7/site-packages/ucsm_apis-0.9.0.0-py2.7.egg/ucsm_apis
查找ucsm_api文件,而不是
/usr/lib/python2.7/site-packages/ucsm_apis-0.9.0.0-py2.7.egg/ucsm_apis
首先。
删除本地版本并从机器版本复制解决了这个问题。
我在fabric_vcon_module文件的import pdb;pdb.set_trace()
函数中嵌入了行setup_fabric_vcon(server, module)
,就在import语句之后。
运行python /[proper_path]/fabric_vcon_module.py /[proper_path]/args_fabric.json
并在pdb中逐行移动显示错误来自fabric_vcon_create(handle=server, **args_mo)
行。
我重新启动pdb以进入该函数,并且对函数的调用向我显示了正在访问的库的文件位置。
{
"ANSIBLE_MODULE_ARGS": {
"id": "1",
"ls_server_dn": "org-root/org-DHS-VM/ls-DS-ESX-C2-SCALEIO",
"fabric": "NONE",
"inst_type": "manual",
"placement": "physical",
"select": "all",
"share": "shared",
"transport": "ethernet, fc",
"state": "present",
"ucs_ip": "10.94.254.136",
"ucs_username": "ansible",
"ucs_password": "elbisna1*"
}
}