一、简介

openstack的各个模块中,都有相应的客户端模块实现,其作用是为用户访问具体模块提供了接口,并且也作为模块之间相互访问的途径。Cinder也一样,有着自己的cinder-client。

二、argparse简单介绍

argparse是python用于解析命令行参数和选项的标准模块,作为optparse的一个替代被添加到Python2.7。Cinder-client主要就是调用了argparse这个工具包。

使用步骤:

import argparse
parser = argparse.ArgumentParser()
parser.add_argument()

parser.parse_args()

首先导入该模块;然后创建一个解析对象;然后向该对象中添加你要关注的命令行参数和选项,每一个add_argument方法对应一个你要关注的参数或选项;最后调用parse_args()方法进行解析;解析成功之后即可使用。
方法 ArgumentParser(prog=None, usage=None,description=None, epilog=None, parents=[],formatter_class=argparse.HelpFormatter, prefix_chars='-',fromfile_prefix_chars=None, argument_default=None,conflict_handler='error', add_help=True)

这些参数都有默认值,当调用 parser.print_help()或者运行程序时,由于参数不正确(此时python解释器其实也是调用了pring_help()方法)时,会打印这些描述信息,一般只需要传递description参数

方法add_argument(name or flags...[, action][, nargs][, const][, default][, type][, choices][, required][, help][, metavar][, dest])
其中:
name or flags:命令行参数名或者选项,如上面的address或者-p,--port.其中命令行参数如果没给定,且没有设置defualt,则出错。但是如果是选项的话,则设置为None。,parse_args()运行时,会用'-'来认证可选参数,剩下的即为位置参数
nargs:命令行参数的个数,一般使用通配符表示,其中,'?'表示只用一个,'*'表示0到多个,'+'表示至少一个。nargs='*' 表示参数可设置零个或多个;nargs=' '+' 表示参数可设置一个或多个;nargs='?'表示参数可设置零个或一个

default:默认值。

type:参数的类型,默认是字符串string类型,还有float、int等类型。
help:和ArgumentParser方法中的参数作用相似,出现的场合也一致。
dest:如果提供dest,例如dest="a",那么可以通过args.a访问该参数
action:参数出发的动作
store:保存参数,默认
store_const:保存一个被定义为参数规格一部分的值(常量),而不是一个来自参数解析而来的值。
store_ture/store_false:保存相应的布尔值
append:将值保存在一个列表中。
append_const:将一个定义在参数规格中的值(常量)保存在一个列表中。
count:参数出现的次数

parser.add_argument("-v", "--verbosity", action="count", default=0, help="increase output verbosity")
version:打印程序版本信息
choice:允许的参数值

三、cinderclient代码入口查找

  1. 第一种方式:
  2. D:\官网代码\python-cinderclient-stable-pike\setup.cfg
  3. [entry_points]
  4. console_scripts =
  5. cinder = cinderclient.shell:main
  6.  
  7. 第二种方式:
  8. [root@test bin]# pwd
  9. /usr/bin
  10. [root@test bin]# ls |grep cinder
  11. cinder
  12. cinder-all
  13. cinder-api
  14. cinder-backup
  15. cinder-manage
  16. cinder-rootwrap
  17. cinder-rtstool
  18. cinder-scheduler
  19. cinder-volume
  20. cinder-volume-usage-audit
  21. [root@test bin]# cat cinder
  22. #!/usr/bin/python
  23. # PBR Generated from u'console_scripts'
  24. import sys
  25. from cinderclient.shell import main
  26.  
  27. if __name__ == "__main__":
  28. sys.exit(main())
  29. [root@test bin]#

四、cinderclient代码分析

  1. D:\官网代码\python-cinderclient-stable-pike\cinderclient\shell.py
  2. def main():
  3. try:
  4. if sys.version_info >= (3, 0):-----sys.version获取python的版本,默认情况下, 使用系统自带的python版本,python2.6或者python 2.7
  5. """
  6. >>> print sys.version_info
  7. (2, 6, 6, 'final', 0)
  8. >>>
  9. """
  10. OpenStackCinderShell().main(sys.argv[1:])---sys.argv[1:],输入的cinder命令行,sys.argv[0]表示程序本身,sys.argv[1:]表示 输入的参数
  11. else:
  12. OpenStackCinderShell().main([encodeutils.safe_decode(item)----走如下分支,步骤一
  13. for item in sys.argv[1:]])
  14. except KeyboardInterrupt:
  15. print("... terminating cinder client", file=sys.stderr)
  16. sys.exit(130)
  17. except Exception as e:
  18. logger.debug(e, exc_info=1)
  19. print("ERROR: %s" % six.text_type(e), file=sys.stderr)
  20. sys.exit(1)

对步骤一进行详解

  1. from cinderclient import api_versions
  2. from cinderclient import client
  3.  
  4. D:\官网代码\python-cinderclient-stable-pike\cinderclient\shell.py
  5. class OpenStackCinderShell(object):
  6.  
  7. def __init__(self):
  8. self.ks_logger = None
  9. self.client_logger = None
  10. def main(self, argv):
  11. # Parse args once to find version and debug settings
  12. 解析args参数一次,查找versiondebug设置信息
  13. parser = self.get_base_parser()
  14. """
  15. get_base_parser:获取基本的命令行解析器;调用add_argument方法实现添加具体命令行参数;
  16. 构造参数解析类ArgumentParser的实例parser,然后通过实例调用方法parser.add_argument增加一些固有的参数,比如:--debug,--help,
  17. --os_auth_type等参数
  18. """
  19. (options, args) = parser.parse_known_args(argv)
  20. """
  21. parse_known_args()方法的作用就是当仅获取到基本设置时,如果运行命令中传入了之后才会获取到的其他配置,不会报错;
  22. 而是将多出来的部分保存起来,留到后面使用,解析的参数按属性的方式存储到Namespace对象;
  23. options的值为命名空间namespace的对象
  24. """
  25. self.setup_debugging(options.debug)----打开debug信息
  26. api_version_input = True
  27. self.options = options
  28.  
  29. do_help = ('help' in argv) or (-----查看是不是需要对命令行进行help查询
  30. '--help' in argv) or ('-h' in argv) or not argv
  31.  
  32. #确定使用API的版本,默认情况下,是版本3
  33. if not options.os_volume_api_version:
  34. api_version = api_versions.get_api_version(
  35. DEFAULT_MAJOR_OS_VOLUME_API_VERSION)
  36. else:
  37. api_version = api_versions.get_api_version(
  38. options.os_volume_api_version)
  39.  
  40. # build available subcommands based on version
  41. #根据api版本号,去查找其对应的版本的扩展版本,其实本质上就是获取
  42. D:\官网代码\python-cinderclient-stable-pike\cinderclient\v2\contrib\list_extensions.py模块中的类
  43. major_version_string = "%s" % api_version.ver_major
  44. self.extensions = client.discover_extensions(major_version_string)
  45. self._run_extension_hooks('__pre_parse_args__')
  46.  
  47. #基于版本api版本,创建对应的子命令解释器,同时根据对应的api_version版本,加载
  48. D:\官网代码\python-cinderclient-stable-pike\cinderclient不同版本的shell.py文件
  49. D:\官网代码\python-cinderclient-stable-pike\cinderclient\v2\shell.py模块
  50. subcommand_parser = self.get_subcommand_parser(api_version,
  51. do_help, args)
  52. self.parser = subcommand_parser
  53.  
  54. if options.help or not argv:---如果命令行后面跟的是help命令,那么就打印该命令的help信息,直接返回
  55. subcommand_parser.print_help()
  56. return 0
  57.  
  58. argv = self._delimit_metadata_args(argv)
  59. # 命令行参数的解析;
  60. args = subcommand_parser.parse_args(argv)
  61. self._run_extension_hooks('__post_parse_args__', args)
  62.  
  63. # Short-circuit and deal with help right away.
  64. if args.func == self.do_help:
  65. self.do_help(args)
  66. return 0
  67. elif args.func == self.do_bash_completion:
  68. self.do_bash_completion(args)
  69. return 0
  70. #提取命令行参数中的基本的租户等信息存放到一个元祖里,为后面方法的调用做具体参数的准备
  71. (os_username, os_password, os_tenant_name, os_auth_url,
  72. os_region_name, os_tenant_id, endpoint_type,
  73. service_type, service_name, volume_service_name, os_endpoint,
  74. cacert, os_auth_type) = (
  75. args.os_username, args.os_password,
  76. args.os_tenant_name, args.os_auth_url,
  77. args.os_region_name, args.os_tenant_id,
  78. args.os_endpoint_type,
  79. args.service_type, args.service_name,
  80. args.volume_service_name,
  81. args.os_endpoint, args.os_cacert,
  82. args.os_auth_type)
  83. auth_session = None
  84. #对参数的认证权限的一些处理,比如是否提供租户、是否提供密码等
  85. if os_auth_type and os_auth_type != "keystone":
  86. auth_plugin = loading.load_auth_from_argparse_arguments(
  87. self.options)
  88. auth_session = loading.load_session_from_argparse_arguments(
  89. self.options, auth=auth_plugin)
  90. else:
  91. auth_plugin = None
  92.  
  93. if not service_type:
  94. service_type = client.SERVICE_TYPES[major_version_string]
  95.  
  96. # FIXME(usrleon): Here should be restrict for project id same as
  97. # for os_username or os_password but for compatibility it is not.
  98.  
  99. # V3 stuff
  100. project_info_provided = ((self.options.os_tenant_name or
  101. self.options.os_tenant_id) or
  102. (self.options.os_project_name and
  103. (self.options.os_project_domain_name or
  104. self.options.os_project_domain_id)) or
  105. self.options.os_project_id)
  106.  
  107. # NOTE(e0ne): if auth_session exists it means auth plugin created
  108. # session and we don't need to check for password and other
  109. # authentification-related things.
  110. if not utils.isunauthenticated(args.func) and not auth_session:
  111. if not os_password:
  112. # No password, If we've got a tty, try prompting for it
  113. if hasattr(sys.stdin, 'isatty') and sys.stdin.isatty():
  114. # Check for Ctl-D
  115. try:
  116. os_password = getpass.getpass('OS Password: ')
  117. # Initialize options.os_password with password
  118. # input from tty. It is used in _get_keystone_session.
  119. options.os_password = os_password
  120. except EOFError:
  121. pass
  122. # No password because we didn't have a tty or the
  123. # user Ctl-D when prompted.
  124. if not os_password:
  125. raise exc.CommandError("You must provide a password "
  126. "through --os-password, "
  127. "env[OS_PASSWORD] "
  128. "or, prompted response.")
  129.  
  130. if not project_info_provided:
  131. raise exc.CommandError(_(
  132. "You must provide a tenant_name, tenant_id, "
  133. "project_id or project_name (with "
  134. "project_domain_name or project_domain_id) via "
  135. " --os-tenant-name (env[OS_TENANT_NAME]),"
  136. " --os-tenant-id (env[OS_TENANT_ID]),"
  137. " --os-project-id (env[OS_PROJECT_ID])"
  138. " --os-project-name (env[OS_PROJECT_NAME]),"
  139. " --os-project-domain-id "
  140. "(env[OS_PROJECT_DOMAIN_ID])"
  141. " --os-project-domain-name "
  142. "(env[OS_PROJECT_DOMAIN_NAME])"
  143. ))
  144.  
  145. if not os_auth_url:
  146. raise exc.CommandError(
  147. "You must provide an authentication URL "
  148. "through --os-auth-url or env[OS_AUTH_URL].")
  149.  
  150. if not project_info_provided:
  151. raise exc.CommandError(_(
  152. "You must provide a tenant_name, tenant_id, "
  153. "project_id or project_name (with "
  154. "project_domain_name or project_domain_id) via "
  155. " --os-tenant-name (env[OS_TENANT_NAME]),"
  156. " --os-tenant-id (env[OS_TENANT_ID]),"
  157. " --os-project-id (env[OS_PROJECT_ID])"
  158. " --os-project-name (env[OS_PROJECT_NAME]),"
  159. " --os-project-domain-id "
  160. "(env[OS_PROJECT_DOMAIN_ID])"
  161. " --os-project-domain-name "
  162. "(env[OS_PROJECT_DOMAIN_NAME])"
  163. ))
  164.  
  165. if not os_auth_url and not auth_plugin:
  166. raise exc.CommandError(
  167. "You must provide an authentication URL "
  168. "through --os-auth-url or env[OS_AUTH_URL].")
  169. #没有提供认证会话的,那么与keystone建立认证会话
  170. if not auth_session:
  171. auth_session = self._get_keystone_session()
  172.  
  173. insecure = self.options.insecure
  174.  
  175. self.cs = client.Client(---------------步骤二,本质上是一个http请求
  176. api_version, os_username,
  177. os_password, os_tenant_name, os_auth_url,
  178. region_name=os_region_name,
  179. tenant_id=os_tenant_id,
  180. endpoint_type=endpoint_type,
  181. extensions=self.extensions,
  182. service_type=service_type,
  183. service_name=service_name,
  184. volume_service_name=volume_service_name,
  185. bypass_url=os_endpoint,
  186. retries=options.retries,
  187. http_log_debug=args.debug,
  188. insecure=insecure,
  189. cacert=cacert, auth_system=os_auth_type,
  190. auth_plugin=auth_plugin,
  191. session=auth_session,
  192. logger=self.ks_logger if auth_session else self.client_logger)
  193.  
  194. try:
  195. # 如果所要调用的方法没有标志为unauthenticated,则需要进行身份验证操作;
  196. if not utils.isunauthenticated(args.func):
  197. self.cs.authenticate()
  198. except exc.Unauthorized:
  199. raise exc.CommandError("OpenStack credentials are not valid.")
  200. except exc.AuthorizationFailure:
  201. raise exc.CommandError("Unable to authorize user.")
  202.  
  203. endpoint_api_version = None
  204. # Try to get the API version from the endpoint URL. If that fails fall
  205. # back to trying to use what the user specified via
  206. # --os-volume-api-version or with the OS_VOLUME_API_VERSION environment
  207. # variable. Fail safe is to use the default API setting.
  208. try:
  209. endpoint_api_version = \
  210. self.cs.get_volume_api_version_from_endpoint()
  211. except exc.UnsupportedVersion:
  212. endpoint_api_version = options.os_volume_api_version
  213. if api_version_input:
  214. logger.warning("Cannot determine the API version from "
  215. "the endpoint URL. Falling back to the "
  216. "user-specified version: %s",
  217. endpoint_api_version)
  218. else:
  219. logger.warning("Cannot determine the API version from the "
  220. "endpoint URL or user input. Falling back "
  221. "to the default API version: %s",
  222. endpoint_api_version)
  223.  
  224. profile = osprofiler_profiler and options.profile
  225. if profile:
  226. osprofiler_profiler.init(options.profile)
  227.  
  228. try:
  229. args.func(self.cs, args)----实现根据解析的命令行参数调用具体的方法,假如使用的命令行为cinder list,该处args.func = do_list
    说明这里调用的具体方法是do_list
  230. finally:
  231. if profile:
  232. trace_id = osprofiler_profiler.get().get_base_id()
  233. print("Trace ID: %s" % trace_id)
  234. print("To display trace use next command:\n"
  235. "osprofiler trace show --html %s " % trace_id)

对步骤二详解

  1. D:\官网代码\python-cinderclient-stable-pike\cinderclient\client.py
  2. def Client(version, *args, **kwargs):
  3. """Initialize client object based on given version."""
  4. api_version, client_class = _get_client_class_and_version(version)----对步骤2.1 详解根据api版本version版本号,获取对应目录下的Client函数
  5. return client_class(api_version=api_version,*args, **kwargs)-------对步骤2.2的详解
  6.  
  7. 对步骤2.1详解
  8. D:\官网代码\python-cinderclient-stable-pike\cinderclient\client.py
  9. def _get_client_class_and_version(version):
  10. if not isinstance(version, api_versions.APIVersion):
  11. version = api_versions.get_api_version(version)
  12. else:
  13. api_versions.check_major_version(version)
  14. if version.is_latest():
  15. raise exceptions.UnsupportedVersion(
  16. _("The version should be explicit, not latest."))
  17. return version, importutils.import_class(
  18. "cinderclient.v%s.client.Client" % version.ver_major)
  19.  
  20. 对步骤2.2 的详解---假如使用的版本为v2版本
  21. D:\官网代码\python-cinderclient-stable-pike\cinderclient\v2\client.py
  22. from cinderclient import client
  23. from cinderclient import api_versions
  24. from cinderclient.v2 import availability_zones
  25. from cinderclient.v2 import cgsnapshots
  26. from cinderclient.v2 import consistencygroups
  27. from cinderclient.v2 import capabilities
  28. from cinderclient.v2 import limits
  29. from cinderclient.v2 import pools
  30. from cinderclient.v2 import qos_specs
  31. from cinderclient.v2 import quota_classes
  32. from cinderclient.v2 import quotas
  33. from cinderclient.v2 import services
  34. from cinderclient.v2 import volumes
  35. from cinderclient.v2 import volume_snapshots
  36. from cinderclient.v2 import volume_types
  37. from cinderclient.v2 import volume_type_access
  38. from cinderclient.v2 import volume_encryption_types
  39. from cinderclient.v2 import volume_backups
  40. from cinderclient.v2 import volume_backups_restore
  41. from cinderclient.v2 import volume_transfers
  42.  
  43. class Client(object):
  44.  
  45. def __init__(self, username=None, api_key=None, project_id=None,
  46. auth_url='', insecure=False, timeout=None, tenant_id=None,
  47. proxy_tenant_id=None, proxy_token=None, region_name=None,
  48. endpoint_type='publicURL', extensions=None,
  49. service_type='volumev2', service_name=None,
  50. volume_service_name=None, bypass_url=None, retries=0,
  51. http_log_debug=False, cacert=None, auth_system='keystone',
  52. auth_plugin=None, session=None, api_version=None,
  53. logger=None, **kwargs):
  54. # FIXME(comstud): Rename the api_key argument above when we
  55. # know it's not being used as keyword argument
  56. password = api_key
  57. self.version = '2.0'
  58. self.limits = limits.LimitsManager(self)
  59.  
  60. # extensions------引入统一目录下,不同资源的管理类
  61. self.volumes = volumes.VolumeManager(self)
  62. self.volume_snapshots = volume_snapshots.SnapshotManager(self)
  63. self.volume_types = volume_types.VolumeTypeManager(self)
  64. self.volume_type_access = \
  65. volume_type_access.VolumeTypeAccessManager(self)
  66. self.volume_encryption_types = \
  67. volume_encryption_types.VolumeEncryptionTypeManager(self)
  68. self.qos_specs = qos_specs.QoSSpecsManager(self)
  69. self.quota_classes = quota_classes.QuotaClassSetManager(self)
  70. self.quotas = quotas.QuotaSetManager(self)
  71. self.backups = volume_backups.VolumeBackupManager(self)
  72. self.restores = volume_backups_restore.VolumeBackupRestoreManager(self)
  73. self.transfers = volume_transfers.VolumeTransferManager(self)
  74. self.services = services.ServiceManager(self)
  75. self.consistencygroups = consistencygroups.\
  76. ConsistencygroupManager(self)
  77. self.cgsnapshots = cgsnapshots.CgsnapshotManager(self)
  78. self.availability_zones = \
  79. availability_zones.AvailabilityZoneManager(self)
  80. self.pools = pools.PoolManager(self)
  81. self.capabilities = capabilities.CapabilitiesManager(self)
  82. self.api_version = api_version or api_versions.APIVersion(self.version)
  83.  
  84. # Add in any extensions...
  85. if extensions:
  86. for extension in extensions:
  87. if extension.manager_class:
  88. setattr(self, extension.name,
  89. extension.manager_class(self))
  90.  
  91. if not logger:
  92. logger = logging.getLogger(__name__)
  93.  
  94. self.client = client._construct_http_client(----本质上就是调用http模块的,建立session连接,同时拼接url的请求头,请求体
  95. username=username,
  96. password=password,
  97. project_id=project_id,
  98. auth_url=auth_url,
  99. insecure=insecure,
  100. timeout=timeout,
  101. tenant_id=tenant_id,
  102. proxy_tenant_id=tenant_id,
  103. proxy_token=proxy_token,
  104. region_name=region_name,
  105. endpoint_type=endpoint_type,
  106. service_type=service_type,
  107. service_name=service_name,
  108. volume_service_name=volume_service_name,
  109. bypass_url=bypass_url,
  110. retries=retries,
  111. http_log_debug=http_log_debug,
  112. cacert=cacert,
  113. auth_system=auth_system,
  114. auth_plugin=auth_plugin,
  115. session=session,
  116. api_version=self.api_version,
  117. logger=logger,
  118. **kwargs)
  119.  
  120. def authenticate(self):
  121. """Authenticate against the server.
  122.  
  123. Normally this is called automatically when you first access the API,
  124. but you can call this method to force authentication right now.
  125.  
  126. Returns on success; raises :exc:`exceptions.Unauthorized` if the
  127. credentials are wrong.
  128. """
  129. self.client.authenticate()
  130.  
  131. def get_volume_api_version_from_endpoint(self):
  132. return self.client.get_volume_api_version_from_endpoint()  

五、添加一个新的命令行,这个命令行的功能为获取卷的连接信息,

1)命令行设计的样式如下所示:

  1. cinder create-target volume_id hostname ip initiator
  2. usage: cinder create [--platform <platform>]
  3. [--do_local_attach <do_local_attach>]
  4. [--os_type <os_type>]
  5. [--multipath <multipath>]
  6. [<volume_id>]
  7. [<host_ip >]
  8. [<host_name>]
  9. [<initiator>]
  10. Creates a volume target.
  11. Positional arguments:
  12. <volume_id> volume uuid
  13. <host_ip > host ip ,which attach volume
  14. <host_name> host name ,which attach volume
  15. <initiator> host iscsi client,which attach volume
  16.  
  17. Optional arguments:
  18. --platform <platform> host architecture ,which attach volume.Default=x86_64
  19. --do_local_attach <do_local_attach> if or not attach volume.Default=None
  20. --os_type <os_type> host operation system,whiic attach volume.Default=linux2
  21. --multipath <multipath> if or not iscsi multipath.Default=None

 

2)代码实现,在v2版本的shell.py文件中新增一个do_create_target函数

  1. D:\官网代码\python-cinderclient-stable-ocata\cinderclient\v2\shell.py
  2. @utils.arg('volume',
  3. metavar='<volume_id>',
  4. help='volume uuid')
  5. @utils.arg('host_ip',
  6. metavar='<host_ip>',
  7. help='host ip ,which attach volume')
  8. @utils.arg('host_name',
  9. metavar='<host_name>',
  10. help='host name ,which attach volume')
  11. @utils.arg('initiator',
  12. metavar='<initiator>',
  13. help='host iscsi client,which attach volume')
  14. @utils.arg('--platform',
  15. metavar='<platform>',
  16. default='x86_64',
  17. help='host architecture ,which attach volume.Default=x86_64')
  18. @utils.arg('--do_local_attach',
  19. metavar='<do_local_attach>',
  20. default='false',
  21. help='if or not attach volume.Default=false')
  22. @utils.arg('--os_type',
  23. metavar='<os_type>',
  24. default='linux2',
  25. help='host operation system,whiic attach volume.Default=linux2')
  26. @utils.arg('--multipath',
  27. metavar='<multipath>',
  28. default='false',
  29. help='if or not iscsi multipath.Default=false')
  30. def do_create_target(cs,args):
  31. """create volume iscsi target."""
  32. volume_id=args.volume
  33. connector={}
  34. connector['ip']=args.host_ip
  35. connector['host']=args.host_name
  36. connector['initiator']=args.initiator
  37. connector['platform']=args.platform
  38. connector['do_local_attach']=args.do_local_attach
  39. connector['os_type']=args.os_type
  40. connector['multipath']=args.multipath
  41. info=cs.volumes.initialize_connection(volume_id,connector)
  42. utils.print_dict(info)

输出内容如下:

  1. [root@test ~]# cinder help create-target
  2. usage: cinder create-target [--platform <platform>]
  3. [--do_local_attach <do_local_attach>]
  4. [--os_type <os_type>] [--multipath <multipath>]
  5. <volume_id> <host_ip> <host_name> <initiator>
  6.  
  7. create volume iscsi target.
  8.  
  9. Positional arguments:
  10. <volume_id> volume uuid
  11. <host_ip> host ip ,which attach volume
  12. <host_name> host name ,which attach volume
  13. <initiator> host iscsi client,which attach volume
  14.  
  15. Optional arguments:
  16. --platform <platform>
  17. host architecture ,which attach volume.Default=x86_64
  18. --do_local_attach <do_local_attach>
  19. if or not attach volume.Default=false
  20. --os_type <os_type> host operation system,whiic attach
  21. volume.Default=linux2
  22. --multipath <multipath>
  23. if or not iscsi multipath.Default=false
  24. [root@test ~]#

3)验证命令行

  1. [root@test ~]# cinder --debug create-target a0ac29de-3a16-4b07-9aac-de63ccdf8fda 10.27.244.149 my03n010027244149.sncloud.com \
    iqn.1994-05.com.redhat:7329936b16d9
  2. DEBUG:keystoneauth:REQ: curl -g -i -X POST http://10.27.241.34:8776/v2/d432ed8741cc427da398e4239f44deb4/volumes/a0ac29de-3a16-4b07-9aac-de63ccdf8fda/action
  3. -H "User-Agent: python-cinderclient"
  4. -H "Content-Type: application/json"
  5. -H "Accept: application/json"
  6. -H "X-Auth-Token: {SHA1}10e60c88cab7620ad3864cb1110d2b9c64a8170f"
  7. -d
  8. {
  9. "os-initialize_connection": {
  10. "connector": {
  11. "initiator": "iqn.1994-05.com.redhat:7329936b16d9",
  12. "ip": "10.27.244.149",
  13. "platform": "x86_64",
  14. "host": "my03n010027244149.sncloud.com",
  15. "do_local_attach": "false",
  16. "os_type": "linux2",
  17. "multipath": "false"
  18. }
  19. }
  20. }
  21.  
  22. RESP BODY:
  23. {
  24. "connection_info": {
  25. "driver_volume_type": "iscsi",
  26. "data": {
  27. "target_luns": [0],
  28. "target_iqns": ["iqn.2010-10.org.openstack:volume-a0ac29de-3a16-4b07-9aac-de63ccdf8fda"],
  29. "auth_password": "24do7AqfnLDZ5DyB",
  30. "target_discovered": false,
  31. "encrypted": false,
  32. "qos_specs": null,
  33. "target_iqn": "iqn.2010-10.org.openstack:volume-a0ac29de-3a16-4b07-9aac-de63ccdf8fda",
  34. "target_portal": "10.27.244.144:3260",
  35. "volume_id": "a0ac29de-3a16-4b07-9aac-de63ccdf8fda",
  36. "target_lun": 0,
  37. "access_mode": "rw",
  38. "auth_username": "2y35wC68BsvU8M37tWCn",
  39. "auth_method": "CHAP",
  40. "target_portals": ["10.27.244.144:3260"]
  41. }
  42. }
  43. }

  

  

 

  

  

 

cinderclient命令行源码解析的更多相关文章

  1. 在远程登陆的主机上通过命令行源码编译安装 GNU M4、autoconf、automake 等程序

    由于实验需要,最近获得了一个实验室服务器的账号,平常主要通过 ssh 进行远程登陆进行实验.一方面,远程登录的机器只提供终端界面,一般只通过命令行进行任务操作:另一方面,由于是多人共享服务器,故而个人 ...

  2. Redis系列(九):数据结构Hash源码解析和HSET、HGET命令

    2.源码解析 1.相关命令如下: {"hset",hsetCommand,,"wmF",,NULL,,,,,}, {"hsetnx",hse ...

  3. Redis系列(十):数据结构Set源码解析和SADD、SINTER、SDIFF、SUNION、SPOP命令

    1.介绍 Hash是以K->V形式存储,而Set则是K存储,空间节省了很多 Redis中Set是String类型的无序集合:集合成员是唯一的. 这就意味着集合中不能出现重复的数据.可根据应用场景 ...

  4. 【原】Android热更新开源项目Tinker源码解析系列之一:Dex热更新

    [原]Android热更新开源项目Tinker源码解析系列之一:Dex热更新 Tinker是微信的第一个开源项目,主要用于安卓应用bug的热修复和功能的迭代. Tinker github地址:http ...

  5. jQuery2.x源码解析(构建篇)

    jQuery2.x源码解析(构建篇) jQuery2.x源码解析(设计篇) jQuery2.x源码解析(回调篇) jQuery2.x源码解析(缓存篇) 笔者阅读了园友艾伦 Aaron的系列博客< ...

  6. 实战录 | Kafka-0.10 Consumer源码解析

    <实战录>导语 前方高能!请注意本期攻城狮幽默细胞爆表,坐地铁的拉好把手,喝水的就建议暂时先别喝了:)本期分享人为云端卫士大数据工程师韩宝君,将带来Kafka-0.10 Consumer源 ...

  7. QT源码解析(一) QT创建窗口程序、消息循环和WinMain函数

    QT源码解析(一) QT创建窗口程序.消息循环和WinMain函数 分类: QT2009-10-28 13:33 17695人阅读 评论(13) 收藏 举报 qtapplicationwindowse ...

  8. Celery 源码解析五: 远程控制管理

    今天要聊的话题可能被大家关注得不过,但是对于 Celery 来说确实很有用的功能,曾经我在工作中遇到这类情况,就是我们将所有的任务都放在同一个队列里面,然后有一天突然某个同学的代码写得不对,导致大量的 ...

  9. junit源码解析--初始化阶段

    OK,我们接着上篇整理.上篇博客中已经列出的junit的几个核心的类,这里我们开始整理junit完整的生命周期. JUnit 的完整生命周期分为 3 个阶段:初始化阶段.运行阶段和结果捕捉阶段. 这篇 ...

随机推荐

  1. 对‘sqrt’未定义的引用

    首先, 引用数学库 #include<math.h> 引用数学库时,要在编译后加上-lm 是每一个都要加!! 如下: gcc su.c -o su.o -lm gcc -g  su.c - ...

  2. FGPA_Microblaze UART 中断

    由于底层所给函数发送与接收都采用中断,所用库函数比较复杂 ,有些更改涉及底层函数,因此结合网上论坛 .百度文库调试了串口中断接收程序.通过串口调试助手发送数据 ,以“发送新行”结束 . 硬件外设波特兰 ...

  3. 不想得手指关节炎?帮你提炼IDEA常用代码补全操作

    一.常用的代码补全操作 1..for和.fori(for 循环遍历) 输入args.for回车(args是一个数组或集合类),则会生成for循环遍历: 输入args.fori回车,则会生成带有索引的f ...

  4. 11-21 logging 模块

    默认情况下Python的logging模块将日志打印到了标准输出中,且只显示了大于等于WARNING级别的日志, 这说明默认的日志级别设置为WARNING(日志级别等级CRITICAL > ER ...

  5. PHP strip_whitespace() 函数

    实例 返回已删除 PHP 注释以及空白字符的 "test.php" 文件的源代码: <?php// PHP comment /** Another PHP comment*/ ...

  6. PDOStatement::setAttribute

    PDOStatement::setAttribute — 设置一个语句属性(PHP 5 >= 5.1.0, PECL pdo >= 0.2.0)高佣联盟 www.cgewang.com 说 ...

  7. 剑指 Offer 58 - II. 左旋转字符串

    本题 题目链接 题目描述 我的题解 方法一:使用库函数 s.substring() 代码如下 public String reverseLeftWords(String s, int n) { ret ...

  8. python4.3内置函数

    常见的内置函数 a=[12,31,31,232,34,32,43,54,36]max1=max(a)#最大函数print(max1)min1=min(a)#最小函数print(min1)sum1=su ...

  9. JDK11.0.7下载及安装详细教程(win10)

    0.背景知识 JRE: Java Runtime Environment JDK:Java Development Kit JRE顾名思义是java运行时环境,包含了java虚拟机,java基础类库. ...

  10. GitLab Admin Area 500 Error

    GitLab Admin Area 500 Error GitLab Admin Area Settings 菜单全部报错 500 解决方法 执行: gitlab-rake cache:clear # ...