我是靠谱客的博主 喜悦皮卡丘,最近开发中收集的这篇文章主要介绍SaltStack Python client API 使用说明,觉得挺不错的,现在分享给大家,希望可以做个参考。

概述

Salt提供了几个与Python应用程序交互的接口。 这些接口通常称为*Client() APIs。 每个客户端都可以从master服务器或minion服务器访问Salt的不同服务。 每类Client API的详细使用信息都会在下文进行说明。

您也可以参考在Github上维护的这一份技术资料:SaltStack Python客户端程序API开发指南

还可以了解下以下信息。

有许多方法可以通过编程方式访问Salt。

可以从CLI脚本以及通过REST接口使用Salt。

请参阅Salt的outputter system系统,以JSON或Shell友好的文本或许多其他格式从Salt检索结构化数据。

请参阅state.event runner程序,以在Shell中使用Salt的事件总线。

Salt的netapi模块提供了通过REST接口从外部访问Salt的功能。 查看netapi模块文档以获取更多信息。

文章目录

    • Salt's opts dictionary - 访问Salt的`opts`配置信息字典的API接口
      • client_config
      • minion_config
    • Salt's Loader Interface - Salt模块加载器的API接口
      • minion_mods
      • raw_mod
      • states
      • grains
      • grain_funcs
    • Salt's Client Interfaces
      • cmd
      • cmd_async
      • cmd_batch
      • cmd_iter
      • cmd_iter_no_block
      • cmd_subset
      • get_cli_returns
      • get_event_iter_returns
      • run_job
    • Salt Caller
      • cmd
    • Salt Proxy Caller
      • cmd
    • RunnerClient
      • asynchronous
      • cmd
      • cmd_async
      • cmd_sync
    • WheelClient
      • asynchronous
      • cmd
      • cmd_async
      • cmd_sync
    • CloudClient
      • action
      • create
      • destroy
      • extra_action
      • full_query(query_type='list_nodes_full')
      • list_images(provider=None)
      • list_locations(provider=None)
      • list_sizes(provider=None)
      • low(fun, low)
      • map_run(path=None, **kwargs)
      • min_query(query_type='list_nodes_min')
      • profile(profile, names, vm_overrides=None, **kwargs)
      • query(query_type='list_nodes')
      • select_query(query_type='list_nodes_select')
    • SSHClient
      • cmd
      • cmd_iter

Salt’s opts dictionary - 访问Salt的opts配置信息字典的API接口

一些客户端需要访问Salt的opts字典。 (这是master配置文件或minion配置文件的字典表示。)

提取opts词典的一种常见模式是存放到环境变量中,或者以其他方式从默认位置获取配置。

client_config

salt.config.client_config(path, env_var=‘SALT_CLIENT_CONFIG’, defaults=None)

功能:加载Master配置文件数据

使用方法:

    import salt.config
    master_opts = salt.config.client_config('/etc/salt/master')

返回Salt Master配置文件的字典,其中包含与在本地运行的Salt Master守护程序进行通信所需的必要选项。 此功能可以为客户端搜索特定的配置,并将其添加到master配置的数据中。

这对于像LocalClient这样的master端操作很有用。

minion_config

salt.config.minion_config(path, env_var=‘SALT_MINION_CONFIG’, defaults=None, cache_minion_id=False, ignore_config_errors=True, minion_id=None, role=‘minion’)

功能:读取minion配置文件并设置特殊选项

这对于Minion端操作(例如Caller类)以及手动运行加载程序接口很有用。

使用方法:

    import salt.config
    minion_opts = salt.config.minion_config('/etc/salt/minion')

Salt’s Loader Interface - Salt模块加载器的API接口

Salt运行环境中的模块是通过特定的加载程序系统加载到内存中的。 这使得模块有使用条件要求(操作系统、操作系统版本、安装的库等),并允许Salt注入特殊变量(__salt____opts__等)。

大多数模块可以手动加载。 这在第三方Python应用程序或编写测试时通常很有用。 但是,某些模块要求并期望其下层系统具有完整的、可运行的Salt系统。 值得注意的是需要从master到minion进行通信的模块,如mine, publish以及 peer模块。 错误信息KeyError: 'master_uri'可能是这种情况的指示。 在这些情况下时,请使用Caller类执行这些模块。

Salt中的每种模块类型都有相应的加载器函数。

minion_mods

salt.loader.minion_mods(opts, context=None, utils=None, whitelist=None, initial_load=False, loaded_base_name=None, notify=False, static_modules=None, proxy=None)

功能:加载执行模块

通过评估每个模块中的__virtual __()函数,返回适用于当前系统的执行模块字典。

Parameters

  • opts (dict) – Salt options 字典
  • context (dict) – 默认在__context__中保存的一个Salt上下文
  • utils (dict) – Salt模块应该可以使用的__utils__实用程序功能。 有关配置的其他信息,请参见salt.config中的utils_dirs。
  • whitelist (list) – 模块的白名单列表
  • initial_load (bool) – 该参数已做废
  • loaded_base_name (str) – 加载的基本名称的一个字符串标记。
  • notify (bool) – 指示应在模块加载完成时触发事件的标志。
    import salt.config
    import salt.loader

    __opts__ = salt.config.minion_config('/etc/salt/minion')
    __grains__ = salt.loader.grains(__opts__)
    __opts__['grains'] = __grains__
    __utils__ = salt.loader.utils(__opts__)
    __salt__ = salt.loader.minion_mods(__opts__, utils=__utils__)
    __salt__['test.ping']()

raw_mod

salt.loader.raw_mod(opts, name, functions, mod=‘modules’)

功能:返回单个加载的原始模块并绕过__virtual__函数

    import salt.config
    import salt.loader

    __opts__ = salt.config.minion_config('/etc/salt/minion')
    testmod = salt.loader.raw_mod(__opts__, 'test', None)
    testmod['test.ping']()

states

salt.loader.states(opts, functions, utils, serializers, whitelist=None, proxy=None)

功能:返回state模块

Parameters

  • opts (dict) – Salt options 字典
  • functions (dict) – minions模块的字典,模块名称为key,函数为value。
    import salt.config
    import salt.loader

    __opts__ = salt.config.minion_config('/etc/salt/minion')
    statemods = salt.loader.states(__opts__, None, None)

grains

salt.loader.grains(opts, force_refresh=False, proxy=None)

功能:返回动态grains的函数以及静态grains的值

由于grains是在启动过程的早期进行计算的,因此grains函数没有__salt____proxy__可用。 在proxy-minion启动时,此函数与proxymodule LazyLoader对象一起调用,因此grains函数可以与其受控设备进行通信。

    import salt.config
    import salt.loader

    __opts__ = salt.config.minion_config('/etc/salt/minion')
    __grains__ = salt.loader.grains(__opts__)
    print __grains__['id']

grain_funcs

salt.loader.grain_funcs(opts, proxy=None)

功能:返回grain 函数

        import salt.config
        import salt.loader

        __opts__ = salt.config.minion_config('/etc/salt/minion')
        grainfuncs = salt.loader.grain_funcs(__opts__)

Salt’s Client Interfaces

class salt.client.LocalClient(c_path=’/etc/salt/master’, mopts=None, skip_perm_errors=False, io_loop=None, keep_loop=False, auto_reconnect=False)

功能:Salt Master上的Salt CLI工具使用的API接口

LocalClient用于向Salt minions发送命令以执行执行模块,并将结果返回给Salt Master。

导入和使用LocalClient必须与Salt Master在同一台计算机上完成,并且必须使用与Salt Master在同一用户上进行。 (除非配置了external_auth,并且执行中包括身份验证凭据)。

注意

LocalClient使用Tornado IOLoop,这在已有的IOLoop中使用LocalClient时会产生问题。 如果与另一个IOLoop合作创建LocalClient,请在创建LocalClient之前创建IOLoop,或者在创建IOLoop时使用ioloop.current(),它将返回LocalClient创建的ioloop。

    import salt.client

    local = salt.client.LocalClient()
    local.cmd('*', 'test.fib', [10])

cmd

cmd(tgt, fun, arg=(), timeout=None, tgt_type=‘glob’, ret=’’, jid=’’, full_return=False, kwarg=None, **kwargs)

功能:以同步的方式在目标minions上执行一个管理命令

cmd方法将执行并等待所有minions答复的超时时间,然后它将立即返回所有minions的数据。

        >>> import salt.client
        >>> local = salt.client.LocalClient()
        >>> local.cmd('*', 'cmd.run', ['whoami'])
        {'jerry': 'root'}

当需要使用更多的关键字参数时:

        local.cmd('*', 'test.arg', ['arg1', 'arg2'], kwarg={'foo': 'bar'})

复合命令可在一次发布中用于多次执行。 函数名称和函数使用的参数在单独的列表中提供,但索引值必须相关,如果不需要参数,则必须使用空列表。

        >>> local.cmd('*', [
                'grains.items',
                'sys.doc',
                'cmd.run',
            ],
            [
                [],
                [],
                ['uptime'],
            ])

Parameters

  • tgt (string or list) – 要执行的目标是哪些minions。 默认值为shell glob。 可由tgt_type选项修改。

  • fun (string or list of strings) – 在指定minions上调用的格式为module.function的模块与函数。 例如test.pinggrains.items

    复合命令

    通过传递一个命令列表,可以在单个发布任务中调用多个功能函数。 这样可以大大降低开销,并加快应用程序与Salt的通信。

    这就要求arg参数是一个lists列表。 Fun列表和arg列表必须按索引进行关联,这意味着不带参数的函数在预期索引处仍必须具有相应的空列表。

  • arg (list or list-of-lists) – 传递给远程功能函数的参数列表。 如果函数不带参数,则除了执行复合命令时,可以省略arg

  • timeout – 等待minions返回结果的超时时间的秒数。

  • tgt_type – tgt类型的取值范围是:

    • glob - Bash glob - 此为默认值
    • list - Python 格式的主机列表
    • grain - 基于grain数值进行匹配
    • grain_pcre - Grain + regex匹配
    • pillar - 使用pillar进行匹配
    • pillar_pcre - Pillar + regex 匹配
    • nodegroup - 使用nodegroup分组匹配
    • range - 使用 Range server 进行匹配
    • compound - 使用复合匹配
    • ipcidr - 使用ip地址或ip地址段进行匹配

    Changed in version 2017.7.0: Renamed from expr_form to tgt_type

  • ret – 使用哪一种returner程序。 传递的值可以是单个returner,也可以是逗号分隔的returner列表,以按顺序在各minions上调用

  • kwarg – 为函数提供的一个关键字参数列表

  • full_return – 默认仅输出作业返回结果,完整返回则还包括了退出代码和其他作业元数据。

  • kwargs – 可选的关键字参数。 使用external_auth时可以传递身份验证凭据。
    例如: local.cmd('*', 'test.ping', username='saltdev', password='saltdev', eauth='pam') 或者: local.cmd('*', 'test.ping', token='5871821ea51754fdcea8153c1c745433')

Returns

一个包含了执行结果的字典,由minion ID作为key。 如果是复合命令则将返回以函数名称为key的子词典。

cmd_async

cmd_async(tgt, fun, arg=(), tgt_type=‘glob’, ret=’’, jid=’’, kwarg=None, **kwargs)

向连接上的minions发送一个异步执行的命令。

Returns

一个 job ID ,如果执行失败则返回0 。
        >>> local.cmd_async('*', 'test.sleep', [300])
        '20131219215921857715'

cmd_batch

cmd_batch(tgt, fun, arg=(), tgt_type=‘glob’, ret=’’, kwarg=None, batch=‘10%’, **kwargs)

一次只对部分的minions执行命令,直至处理完全部的minions。

Parameters

batch ,按指定比例分批执行

Returns

一个包含了minion返回结果的生成器。

        >>> returns = local.cmd_batch('*', 'state.highstate', batch='10%')
        >>> for ret in returns:
        ...     print(ret)
        {'jerry': {...}}
        {'dave': {...}}
        {'stewart': {...}}

cmd_iter

cmd_iter(tgt, fun, arg=(), timeout=None, tgt_type=‘glob’, ret=’’, kwarg=None, **kwargs)

当minion连接上来时,执行管理命令并生成返回数据。

通常,对于未连接的minions,cmd_iter()不会产生结果。 如果您希望它返回未连接的minions的结果,请在kwargs中设置Expect_minions=True

Returns

一个基于单个minion,依次生成返回数据的生成器。

        >>> ret = local.cmd_iter('*', 'test.ping')
        >>> for i in ret:
        ...     print(i)
        {'jerry': {'ret': True}}
        {'dave': {'ret': True}}
        {'stewart': {'ret': True}}

cmd_iter_no_block

cmd_iter_no_block(tgt, fun, arg=(), timeout=None, tgt_type=‘glob’, ret=’’, kwarg=None, show_jid=False, verbose=False, **kwargs)

当minion连接过来时,为单个minion生成返回数据,如果没有有效的结果数据则返回None。

Returns

一个生成器,基于单个minion生成返回数据,或者当没有返回可用时,返回None。 这允许在minions返回之间注入特定的动作。

        >>> ret = local.cmd_iter_no_block('*', 'test.ping')
        >>> for i in ret:
        ...     print(i)
        None
        {'jerry': {'ret': True}}
        {'dave': {'ret': True}}
        None
        {'stewart': {'ret': True}}

cmd_subset

cmd_subset(tgt, fun, arg=(), tgt_type=‘glob’, ret=’’, kwarg=None, sub=3, cli=False, progress=False, full_return=False, **kwargs)

在目标系统的随机子集上执行命令。

Parameters

  • sub – 目标系统子集中的目标数量
  • cli – 当设置了这个参数时, 返回一个生成器, 否则返回一个包含了minions返回数据的字典。
        >>> SLC.cmd_subset('*', 'test.ping', sub=1)
        {'jerry': True}

get_cli_returns

get_cli_returns(jid, minions, timeout=None, tgt=’*’, tgt_type=‘glob’, verbose=False, show_jid=False, **kwargs)

启动观察程序,查看指定JID的返回数据

Returns

JID的所有信息。

get_event_iter_returns

get_event_iter_returns(jid, minions, timeout=None)

收集事件系统的返回数据,在达到超时时即中止。

run_job

run_job(tgt, fun, arg=(), tgt_type=‘glob’, ret=’’, timeout=None, jid=’’, kwarg=None, listen=False, **kwargs)

异步发送命令到连接的minions。

准备作业目录,并将命令发布到任何目标minions。

Returns

(已验证的)pub_data字典或失败时为空的字典。 pub_data包含作业ID和所有期望返回数据的minions的列表。

        >>> local.run_job('*', 'test.sleep', [300])
        {'jid': '20131219215650131543', 'minions': ['jerry']}

Salt Caller

class salt.client.Caller(c_path=’/etc/salt/minion’, mopts=None)

Caller与Salt Minion上的salt-call命令行工具使用的API接口相同。

Changed in version 2015.8.0:添加了cmd方法以与其他Salt客户端保持一致。 现有的function和sminion.functions接口仍然存在,但已从文档中删除。

导入和使用Caller必须与Salt Minion在同一台计算机上完成,并且必须使用运行Salt Minion的同一用户来完成。

使用方法:

    import salt.client
    caller = salt.client.Caller()
    caller.cmd('test.ping')

注意,使用该类时并不需要运行中的master或minion守护程序。 运行salt-call --local只是将file_client设置为“local”。 通过在minion配置文件中包含该设置,可以在Python级别上实现相同的目的。

  • New in version 2014.7.0*: 将minion配置文件作为 mopts 字典传入。
    import salt.client
    import salt.config
    __opts__ = salt.config.minion_config('/etc/salt/minion')
    __opts__['file_client'] = 'local'
    caller = salt.client.Caller(mopts=__opts__)

cmd

cmd(fun, *args, **kwargs)

用给定的参数和关键字参数调用执行模块。

Changed in version 2015.8.0:添加了cmd方法以与其他Salt客户端保持一致。 现有的function和sminion.functions接口仍然存在,但已从文档中删除。

        caller.cmd('test.arg', 'Foo', 'Bar', baz='Baz')

        caller.cmd('event.send', 'myco/myevent/something',
            data={'foo': 'Foo'}, with_env=['GIT_COMMIT'], with_grains=True)

Salt Proxy Caller

class salt.client.ProxyCaller(c_path=’/etc/salt/proxy’, mopts=None)

ProxyCaller与在Salt Proxy Minion上使用Salt-call通过参数--proxyid <proxyid>执行命令所使用的接口相同。

导入和使用ProxyCaller必须与Salt Minion在同一台计算机上完成,并且必须使用与运行Salt Minion的同一用户完成。

使用方法:

    import salt.client
    caller = salt.client.Caller()
    caller.cmd('test.ping')

注意

使用该类时不需要依赖于运行中的master或minion守护程序。 运行salt-call --local只是将file_client设置为local。 通过在minion配置文件中包含该设置,也可以在Python级别上实现相同的目的。

    import salt.client
    import salt.config
    __opts__ = salt.config.proxy_config('/etc/salt/proxy', minion_id='quirky_edison')
    __opts__['file_client'] = 'local'
    caller = salt.client.ProxyCaller(mopts=__opts__)

注意

要使用它来调用proxies,is_proxy函数要求--proxyid是用于此脚本的一个命令行参数,或者字符串proxy位于脚本名称中。

cmd

cmd(fun, *args, **kwargs)

使用提供的位置参数和关键字参数调用一个执行模块。

        caller.cmd('test.arg', 'Foo', 'Bar', baz='Baz')

        caller.cmd('event.send', 'myco/myevent/something',
            data={'foo': 'Foo'}, with_env=['GIT_COMMIT'], with_grains=True)

RunnerClient

class salt.runner.RunnerClient(opts)

Salt Master上的Salt-run CLI工具使用的接口。

它执行在Salt Master上运行的runner modules程序模块。

导入和使用RunnerClient必须与Salt Master在同一台计算机上进行,并且必须使用与运行Salt Master服务相同的用户。

Salt的external_auth可用于对调用请求进行验证。 必须授权eauth用户执行runner程序模块:(@runner)。 仅下面的master_call()支持eauth。

asynchronous

asynchronous(fun, low, user=‘UNKNOWN’, pub=None)

多进程并发执行该函数,然后返回一个事件标记以用于观察返回数据。

cmd

cmd(fun, arg=None, pub_data=None, kwarg=None, print_event=True, full_return=False)

执行一个函数。

cmd_async

cmd_async(low)

异步执行runner 函数; 支持eauth。

此函数需要配置external_auth,并且用户需要有权执行runner程序功能:(@runner)。

        runner.eauth_async({
            'fun': 'jobs.list_jobs',
            'username': 'saltdev',
            'password': 'saltdev',
            'eauth': 'pam',
        })

cmd_sync

cmd_sync(low, timeout=None, full_return=False)

同步执行一个runner函数; 支持eauth。

此函数需要配置external_auth,并且用户需要有权执行runner程序功能:(@runner)。

        runner.eauth_sync({
            'fun': 'jobs.list_jobs',
            'username': 'saltdev',
            'password': 'saltdev',
            'eauth': 'pam',
        })

WheelClient

class salt.wheel.WheelClient(opts=None)

Salt wheel模块的接口。

Wheel模块与Salt Master的各个部分都有交互。

导入和使用WheelClient必须与Salt Master在同一台计算机上进行,并且必须与运行Salt Master的用户也相同。 需要配置external_auth且用户有权执行wheel功能函数:(@wheel)。

使用方法:

    import salt.config
    import salt.wheel
    opts = salt.config.master_config('/etc/salt/master')
    wheel = salt.wheel.WheelClient(opts)

asynchronous

asynchronous(fun, low, user=‘UNKNOWN’, pub=None)

多进程并发执行该函数,然后返回一个事件标记以用于观察返回数据。

cmd

cmd(fun, arg=None, pub_data=None, kwarg=None, print_event=True, full_return=False)

执行一个函数。

        >>> wheel.cmd('key.finger', ['jerry'])
        {'minions': {'jerry': '5d:f6:79:43:5e:d4:42:3f:57:b8:45:a8:7e:a4:6e:ca'}}

cmd_async

cmd_async(low)

异步执行runner 函数; 支持eauth。

此函数需要配置external_auth,并且用户需要有权执行runner程序功能:(@wheel)。

        >>> wheel.cmd_async({
            'fun': 'key.finger',
            'match': 'jerry',
            'eauth': 'auto',
            'username': 'saltdev',
            'password': 'saltdev',
        })
        {'jid': '20131219224744416681', 'tag': 'salt/wheel/20131219224744416681'}

cmd_sync

cmd_sync(low, timeout=None, full_return=False)

同步执行runner 函数; 支持eauth。

此函数需要配置external_auth,并且用户需要有权执行runner程序功能:(@wheel)。

        >>> wheel.cmd_sync({
        'fun': 'key.finger',
        'match': 'jerry',
        'eauth': 'auto',
        'username': 'saltdev',
        'password': 'saltdev',
        })
        {'minions': {'jerry': '5d:f6:79:43:5e:d4:42:3f:57:b8:45:a8:7e:a4:6e:ca'}}

CloudClient

class salt.cloud.CloudClient(path=None, opts=None, config_dir=None, pillars=None)

一个包装云平台交互接口的客户端类。

action

action(fun=None, cloudmap=None, names=None, provider=None, instance=None, kwargs=None)

通过云插件后端执行单个的操作。

例如:

        client.action(fun='show_instance', names=['myinstance'])
        client.action(fun='show_image', provider='my-ec2-config',
            kwargs={'image': 'ami-10314d79'}
        )

create

create(provider, names, **kwargs)

使用命令创建指定名称的VM,而不是使用配置文件。

例如:

        client.create(provider='my-ec2-config', names=['myinstance'],
            image='ami-1624987f', size='t1.micro', ssh_username='ec2-user',
            securitygroup='default', delvol_on_destroy=True)

destroy

destroy(names)

销毁指定命名的VMs。

extra_action

extra_action(names, provider, action, **kwargs)

使用块存储设备执行相关操作。

例如:

        client.extra_action(names=['myblock'], action='volume_create',
            provider='my-nova', kwargs={'voltype': 'SSD', 'size': 1000}
        )
        client.extra_action(names=['salt-net'], action='network_create',
            provider='my-nova', kwargs={'cidr': '192.168.100.0/24'}
        )

full_query(query_type=‘list_nodes_full’)

查询所有实例的信息。

list_images(provider=None)

列出在云平台中所有可用的镜像。

list_locations(provider=None)

列出在云平台中所有可用的locations。

list_sizes(provider=None)

列出云平台中所有可用的sizes。

low(fun, low)

传递云管理函数和运行使用的low data数据。

map_run(path=None, **kwargs)

执行一个map操作。

min_query(query_type=‘list_nodes_min’)

查询选定实例的信息。

profile(profile, names, vm_overrides=None, **kwargs)

传递一个创建VMs使用的配置文件,names参数是一个包括了待创建VMs名称的列表。

vm_overrides是一个特殊的字典,它将被每个节点的选项覆盖。

例如:

        >>> client= salt.cloud.CloudClient(path='/etc/salt/cloud')
        >>> client.profile('do_512_git', names=['minion01',])
        {'minion01': {'backups_active': 'False',
                'created_at': '2014-09-04T18:10:15Z',
                'droplet': {'event_id': 31000502,
                             'id': 2530006,
                             'image_id': 5140006,
                             'name': 'minion01',
                             'size_id': 66},
                'id': '2530006',
                'image_id': '5140006',
                'ip_address': '107.XXX.XXX.XXX',
                'locked': 'True',
                'name': 'minion01',
                'private_ip_address': None,
                'region_id': '4',
                'size_id': '66',
                'status': 'new'}}

query(query_type=‘list_nodes’)

查询实例的基础信息。

select_query(query_type=‘list_nodes_select’)

查询选定实例的信息。

SSHClient

class salt.client.ssh.client.SSHClient(c_path=’/etc/salt/master’, mopts=None, disable_custom_roster=False)

创建一个用于通过salt-ssh后端执行例行任务的客户端对象。

New in version 2015.5.0.

cmd

cmd(tgt, fun, arg=(), timeout=None, tgt_type=‘glob’, kwarg=None, **kwargs)

通过salt-ssh子系统执行单个命令并立即返回所有例程。

New in version 2015.5.0.

cmd_iter

cmd_iter(tgt, fun, arg=(), timeout=None, tgt_type=‘glob’, ret=’’, kwarg=None, **kwargs)

通过salt-ssh子系统执行一个命令并返回一个生成器。

New in version 2015.5.0.

最后

以上就是喜悦皮卡丘为你收集整理的SaltStack Python client API 使用说明的全部内容,希望文章能够帮你解决SaltStack Python client API 使用说明所遇到的程序开发问题。

如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(45)

评论列表共有 0 条评论

立即
投稿
返回
顶部