ansible ad-hoc及常用模块

Ansible ad-hoc

一、ad-hoc概述

  • 什么ad-hoc

ad-hoc简而言之就是"临时命令",执行完即结束,并不会保存
  • 使用场景

比如在多台机器上查看某个进程是否启动,或拷贝指定文件到本地,等等
临时使用的命令,一次使用
  • ad-hoc模式的命令使用

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-vM45dy4D-1623253595115)(img/image-20201217185959255.png)]

[root@m01 ~]# ansible web01 -m command -a 'df -h'
web01 | CHANGED | rc=0 >>
Filesystem      Size  Used Avail Use% Mounted on
/dev/sda3        18G  1.6G   17G   9% /
devtmpfs        476M     0  476M   0% /dev
tmpfs           487M     0  487M   0% /dev/shm
tmpfs           487M  7.7M  479M   2% /run
tmpfs           487M     0  487M   0% /sys/fs/cgroup
/dev/sda1      1014M  127M  888M  13% /boot
tmpfs            98M     0   98M   0% /run/user/0

[root@m01 ~]# ansible web_group -m command -a 'free -m'
web01 | CHANGED | rc=0 >>
              total        used        free      shared  buff/cache   available
Mem:            972         128         481           7         362         658
Swap:          1023           0        1023
web02 | CHANGED | rc=0 >>
              total        used        free      shared  buff/cache   available
Mem:            972         111         551           7         309         691
Swap:          1023           0        1023
  • ad-hoc结果返回颜色

绿色: 代表被管理端主机没有被修改
黄色: 代表被管理端主机发现变更
红色: 代表出现了故障,注意查看提示
  • ad-hoc常用模块

command             # 执行shell命令(不支持管道等特殊字符)
shell               # 执行shell命令(支持特殊字符)
scripts             # 执行shell脚本
yum_repository      # 配置yum仓库
yum                 # 安装软件
copy                # 变更配置文件
file                # 建立目录或文件
service             # 启动与停止服务
systemd             # 启动与停止服务
mount               # 挂载设备
cron                # 定时任务
get_url             # 下载软件
firewalld           # 防火墙
selinux             # selinux
setup				# 获取主机信息
  • ansible帮助

#1.查看所有模块
[root@m01 ~]# ansible-doc -l

#2.查看指定模块的用法
[root@m01 ~]# ansible-doc yum

#3.查看模块参数
[root@m01 ~]# ansible-doc -s yum

Ansible 常用模块

一、命令模块

  • command模块

#默认模块,远程执行命令
[root@m01 ~]# ansible web01 -m command -a 'free -m'
web01 | CHANGED | rc=0 >>
              total        used        free      shared  buff/cache   available
Mem:            972         128         479           7         364         658
Swap:          1023           0        1023

#不支持特殊字符
[root@m01 ~]# ansible web01 -m command -a "ifconfig eth0 | awk 'NR==2 {print \$2}'"
web01 | FAILED | rc=1 >>
|: Unknown host
ifconfig: `--help' gives usage information.non-zero return code
  • shell模块

[root@m01 ~]# ansible web01 -m shell -a 'free -m'
web01 | CHANGED | rc=0 >>
              total        used        free      shared  buff/cache   available
Mem:            972         128         479           7         364         658
Swap:          1023           0        1023

#支持特殊字符
[root@m01 ~]# ansible web01 -m shell -a "ifconfig eth0 | awk 'NR==2 {print \$2}'"
web01 | CHANGED | rc=0 >>
10.0.0.7
  • scripts 模块

[root@m01 ~]# vim mkdir.sh 
#!/bin/bash
mkdir /dir

#远程执行脚本
[root@m01 ~]# ansible web_group -m script -a 'mkdir.sh'          
web02 | CHANGED => {
    "changed": true, 
    "rc": 0, 
    "stderr": "Shared connection to web02 closed.\r\n", 
    "stderr_lines": [
        "Shared connection to web02 closed."
    ], 
    "stdout": "", 
    "stdout_lines": []
}
web01 | CHANGED => {
    "changed": true, 
    "rc": 0, 
    "stderr": "Shared connection to web01 closed.\r\n", 
    "stderr_lines": [
        "Shared connection to web01 closed."
    ], 
    "stdout": "", 
    "stdout_lines": []
}

#查看
[root@m01 ~]# ansible web_group -m shell -a 'ls -ld /dir'
web01 | CHANGED | rc=0 >>                                   
drwxr-xr-x. 2 root root 6 Dec 18 08:40 /dir
web02 | CHANGED | rc=0 >>
drwxr-xr-x 2 root root 6 Dec 18 08:40 /dir

二、软件管理模块

  • yum模块

[root@m01 ~]# ansible-doc yum
EXAMPLES:
- name: install the latest version of Apache
  yum:
    name: httpd
    state: latest
    
name:
	httpd					   #服务名字
	file					   #软件包的名字
	http://nginx.org/...		#软件包在网上的地址
state:
	latest		#安装最新版本的包
	absent		#卸载软件包
	present		#安装软件包
	
#直接yum安装服务httpd
[root@m01 ~]# ansible web_group -m yum -a 'name=httpd state=present'
相当于在远程机器上执行:yum install -y httpd

#安装本地的rpm包(包一定先传到远程机器上)
[root@m01 ~]# ansible web_group -m yum -a 'name=/tmp/nginx-1.16.1-1.el7.ngx.x86_64.rpm state=present'
相当于在远程机器上执行:yum localinstall -y /tmp/nginx-1.16.1-1.el7.ngx.x86_64.rpm

#安装云上的服务
[root@m01 ~]# ansible web_group -m yum -a 'name=https://mirrors.aliyun.com/zabbix/zabbix/4.0/rhel/7/x86_64/zabbix-agent-4.0.0-2.el7.x86_64.rpm state=present'
相当于在远程机器上执行:yum install -y https://mirrors.aliyun.com/zabbix/zabbix/4.0/rhel/7/x86_64/zabbix-agent-4.0.0-2.el7.x86_64.rpm

#卸载服务包
[root@m01 ~]# ansible web_group -m yum -a 'name=httpd state=absent'
  • yum_repository 模块

[root@m01 ~]# ansible-doc yum_repository
EXAMPLES:
- name: Add repository
  yum_repository:
    name: epel
    description: EPEL YUM repo
    baseurl: https://download.fedoraproject.org/pub/epel/$releasever/$basearch/
    file: external_repos
    enabled: no
    state: absent

#添加yum源
[root@m01 ~]# ansible web_group -m yum_repository -a 'name=nginx.repo description="nginx stable repo" baseurl="http://nginx.org/packages/centos/7/$basearch/" enabled=1 gpgcheck=1 file=nginx state=present'

#查看添加的yum源
[root@web01 ~]# cat /etc/yum.repos.d/nginx.repo
[nginx.repo]
baseurl = http://nginx.org/packages/centos/7/$basearch/
enabled = 1
gpgcheck = 1
name = nginx stable repo

#参数介绍
name			#yum源中 [] 里面的内容
description		#yum源中 name 部分的内容
baseurl			#yum源中 yum 仓库的地址
gpgcheck		#yum源中 gpgcheck,是否检查yum源
enabled			#yum源中的 enabled,是否开启yum源
file			#yum源的文件名字

#注意:
	1.file参数不修改,name参数也不修改的前提下,是修改yum源
	2.file参数不修改,name参数修改的情况下,是添加yum源

三、文件管理模块

  • copy 模块

语法

[root@m01 ~]# ansible-doc copy
EXAMPLES:
- name: Copy file with owner and permissions
  copy:
    src: /srv/myfiles/foo.conf
    dest: /etc/foo.conf
    owner: foo
    group: foo
    mode: '0644'
    backup: yes
    content: '# This file was moved to /etc/other.conf'
    follow: yes
    
src			#文件的源地址
dest		#目标地址或文件
owner		#文件属主
group		#文件属组
mode		#文件的权限
backup		#替换的文件是否备份
content		#直接将内容写入文件
follow		#处理软连接

例子

#推送yum源文件到远端
[root@m01 ~]# ansible web_group -m copy -a 'src=/root/nginx.repo dest=/etc/yum.repos.d/'

#推送rsync密码文件授权
[root@m01 ~]# ansible web_group -m copy -a 'src=/root/1.txt dest=/etc/rsync.passwd mode=600'

#推送站点文件并授权属主属组
[root@m01 ~]# ansible web_group -m copy -a 'src=/root/index.html dest=/root/ owner=adm group=adm'

#推送文件并备份
[root@m01 ~]# ansible web_group -m copy -a 'src=/root/index.html dest=/root/ owner=adm group=adm backup=yes'
注意:buckup参数不是用来回滚的,需要回滚的话要备份原来m01上推送的文件

#直接将内容写入文件
[root@m01 ~]# ansible web_group -m copy -a 'content="rsync_backup:123456" dest=/tmp/rsync.password mode=600'
  • file模块

语法和参数

[root@m01 ~]# ansible-doc file
EXAMPLES:
- name: Change file ownership, group and permissions
  file:
  	src: /file/to/link/to
    path: /etc/foo.conf
    owner: foo
    group: foo
    mode: '0644'
    state: link
    recurse: yes
    
path		#创建的文件或目录的地址
owner		#文件或目录的属主
group		#文件或目录的属组
mode		#文件或目录的权限
state
	link		#创建软链接
		src		#源文件
		dest	#软链接的名字
	touch		#创建文件
	directory	#创建目录
	absent		#删除,目录,文件,软链接
recurse		#递归授权

实例

#单纯的创建目录
[root@m01 ~]# ansible web01 -m file -a 'path=/code state=directory'
相当于在远程机器上执行:mkdir /code

#创建目录并授权
[root@m01 ~]# ansible web01 -m file -a 'path=/code state=directory owner=nginx group=nginx'
相当于在远程机器上执行:mkdir /code && chown nginx.nginx /code

#递归创建目录,不需要加任何参数
[root@m01 ~]# ansible web01 -m file -a 'path=/code/wordpress/wp-content/pic state=directory'

#递归授权目录
[root@m01 ~]# ansible web01 -m file -a 'path=/code/ state=directory owner=nginx group=nginx recurse=yes'

#注意:
	1.当创建的目录不存在时,递归创建会递归授权
	2.当创建的目录已经存在,递归授权只授权最后一层目录下的内容
	
#创建文件
[root@m01 ~]# ansible web01 -m file -a 'path=/tmp/1.txt state=touch'

#创建文件并授权
[root@m01 ~]# ansible web01 -m file -a 'path=/tmp/1.txt state=touch owner=nginx group=nginx'

#创建软链接
[root@m01 ~]# ansible web01 -m file -a 'src=/tmp/1.txt dest=/tmp/1.ln state=link'
  • get_url模块

语法和参数

[root@m01 ~]# ansible-doc get_url
EXAMPLES:
- name: Download foo.conf
  get_url:
    url: http://example.com/path/file.conf
    dest: /etc/foo.conf
    mode: '0440'
    checksum: sha256:b5bb9d8014a0f9b1d61e21e796d78dccdf1352f23cd32812f4850b878ae4944c
 
url			#文件下载地址
dest		#文件存放路径
mode		#文件下载后授权
checksum	#验证文件
	sha256	#加密方式

实例

#下载网站上的文件
[root@m01 ~]# ansible web01 -m get_url -a 'url=http://10.0.0.7/1.txt dest=/tmp'

#下载时验证文件
[root@m01 ~]# ansible web01 -m get_url -a 'url=http://10.0.0.7/1.txt dest=/tmp checksum=md5:d8e8fca2dc0f896fd7cb4cb0031ba249'

四、Ansible 服务管理模块

  • service

[root@m01 ~]# ansible-doc service
EXAMPLES:
- name: Start service httpd, if not started
  service:
    name: httpd
    state: started
    
name: nginx			#服务名字
state:
	started			#启动服务
	stopped			#停止服务
	restarted		#重启服务
	reloaded		#重载服务
enabled: yes		#开机自启
  • systemd

语法和参数

[root@m01 ~]# ansible-doc systemd
EXAMPLES:
- name: Make sure a service is running
  systemd:
    state: started
    name: httpd

name: nginx			#服务名字
state:
	started			#启动服务
	stopped			#停止服务
	restarted		#重启服务
	reloaded		#重载服务
enabled=yes		#开机自启

实例

#关闭服务
[root@m01 ~]# ansible web01 -m systemd -a 'name=nginx state=stopped'

#启动服务
[root@m01 ~]# ansible web01 -m systemd -a 'name=nginx state=started'

五、用户管理模块

  • group 模块

语法和参数

[root@m01 ~]# ansible-doc group
EXAMPLES:
- name: Ensure group "somegroup" exists
  group:
    name: somegroup			#组名字
    state: 
    	present				#创建组
        absent				#删除组
    gid: 666				#指定组id

实例

#创建用户组
[root@m01 ~]# ansible web01 -m group -a 'name=www gid=666 state=present'

#修改用户组
[root@m01 ~]# ansible web01 -m group -a 'name=www gid=666 state=absent'
  • user 模块

语法和参数

[root@m01 ~]# ansible-doc user
EXAMPLES:
- name: Add the user 'johnd' with a specific uid and a primary group of 'admin'
  user:
    name: johnd
    comment: John Doe
    uid: 1040
    group: admin
    shell: /bin/bash
    state: absent
    remove: yes
    create_home: false

name		#用户名字
comment		#用户备注
uid			#用户id
group		#用户所在的组名字

shell:
	/bin/bash	#用户可以登录
	/sbin/nologin	#用户不需要登录
state:
	absent		#删除用户
	present		#创建用户
	
remove			#移除家目录

create_home:	#是否创建家目录
	true		#创建家目录
	false		#不创建家目录

实例

#创建用户,不需要登录,有家目录
[root@m01 ~]# ansible web01 -m user -a 'name=www uid=666 group=www shell=/sbin/nologin create_home=true'

#删除用户并移除家目录
[root@m01 ~]# ansible web01 -m user -a 'name=www state=absent remove=yes'

#注意:
	1.当组的名字与用户名字相同时,删除用户组也会被删除
	2.当组的名字与用户名字相同时,而组下面还有其他用户,则删除用户时不会删除同名组

六、其他模块

  • cron 定时任务模块

语法和参数

[root@m01 ~]# ansible-doc cron
EXAMPLES:
- name: Ensure a job that runs at 2 and 5 exists. Creates an entry like "0 5,2 * * ls -alh > /dev/null"
  cron:
    name: "check dirs"
    minute: "0"
    hour: "5,2"
    day: "*"
    month: "*"
    weekday: "*"
    job: "ls -alh > /dev/null"
    state: absent
    disabled: yes
   
name		#定时任务的备注
minute		#分钟
hour		#小时
day			#日
month		#月
weekday		#周
job			#指定的定时任务内容
state
	present	#新建定时任务
	absent	#删除定时任务
disabled
	yes		#注释定时任务
	no		#取消注释

实例

#添加定时任务,每五分钟执行一次时间同步(只配置分钟,其他不配置默认是 * )
[root@m01 ~]# ansible web01 -m cron -a 'name="测试ansible配置定时任务" minute=*/5 job="ntpdate time1.aliyun.com"'
#查看配置
[root@web01 html]# crontab -l
#Ansible: 测试ansible配置定时任务
*/5 * * * * ntpdate time1.aliyun.com

#注释定时任务
[root@m01 ~]# ansible web01 -m cron -a 'name="测试ansible配置定时任务" minute=*/5 job="ntpdate time1.aliyun.com" disabled=yes'

#删除定时任务
[root@m01 ~]# ansible web01 -m cron -a 'name="测试ansible配置定时任务" minute=*/5 job="ntpdate time1.aliyun.com" state=absent'

#注意:
	1.定时任务添加,是通过名字来区分是否一样的,如果不加name参数,则会添加重复的定时任务
	2.定时任务注释是通过 name 参数来注释的,所以一定要加 name 参数
	3.定时任务删除是通过 name 参数来删除的,所以一定要加 name 参数
  • mount 挂载模块

安装NFS

1.安装nfs
[root@m01 ~]# ansible nfs_server -m yum -a 'name=nfs-utils state=present'

2.配置nfs
[root@m01 ~]# ansible nfs_server -m copy -a 'content="/data 172.16.1.0/24(rw,sync,all_squash)" dest=/etc/exports'

3.创建目录
[root@m01 ~]# ansible nfs_server -m file -a 'path=/data state=directory owner=nfsnobody group=nfsnobody'

4.启动服务
[root@m01 ~]# ansible nfs_server -m systemd -a 'name=nfs state=started'

挂载模块语法和参数

[root@m01 ~]# ansible-doc mount
EXAMPLES:
- name: Mount DVD read-only
  mount:
    path: /mnt/dvd
    src: /dev/sr0
    fstype: iso9660
    opts: ro,noauto
    state: present
    
path		#本机准备挂载的目录
src			#远端挂载点
fstype		#指定挂载类型
opts		#挂载参数(/etc/fstab中的内容)
state
	present		#配置开机挂载,将配置写入自动挂载文件,并没有直接挂载
	unmounted	#取消挂载,但是没有删除自动挂载配置
	#常用配置
	mounted		#配置开机挂载,并且直接挂载上
	absent		#取消挂载,并且删除自动挂载配置

实例

#配置开机挂载,将配置写入自动挂载文件,并没有直接挂载
[root@m01 ~]# ansible web01 -m mount -a 'path=/data src=172.16.1.31:/data fstype=nfs opts=defaults state=present'

#配置开机挂载,并且直接挂载上
[root@m01 ~]# ansible web01 -m mount -a 'path=/data src=172.16.1.31:/data fstype=nfs opts=defaults state=mounted'

#取消挂载,但是没有删除自动挂载配置
[root@m01 ~]# ansible web01 -m mount -a 'path=/data src=172.16.1.31:/data fstype=nfs opts=defaults state=unmounted'

#取消挂载,并且删除自动挂载配置
[root@m01 ~]# ansible web01 -m mount -a 'path=/data src=172.16.1.31:/data fstype=nfs opts=defaults state=absent
  • selinux模块

- name: Disable SELinux
  selinux:
    state: disabled

#关闭selinux
[root@m01 ~]# ansible web02 -m selinux -a 'state=disabled'
web02 | SUCCESS => {
    "ansible_facts": {
        "discovered_interpreter_python": "/usr/bin/python"
    }, 
    "changed": false, 
    "configfile": "/etc/selinux/config", 
    "msg": "", 
    "policy": "targeted", 
    "reboot_required": false, 
    "state": "disabled"
}
  • firewalld 模块

语法和参数

[root@m01 ~]# ansible-doc firewalld
EXAMPLES:
- firewalld:
    service: https			#指定服务
    permanent: 				#是否永久生效
    	yes					#永久生效
    	no					#临时生效
    state: 
    	enabled			    #允许通过
    port: 
    	8081/tcp			#指定端口
    zone: dmz				#指定区域
    rich_rule: rule service name="ftp" audit limit value="1/m" accept		#配置富规则
    source: 192.0.2.0/24	#指定网段
    interface: eth2			#绑定网卡
    masquerade: yes			#开启IP伪装

实例

#允许访问http服务,永久生效
[root@m01 ~]# ansible web01 -m firewalld -a 'service=http permanent=yes state=enabled'
[root@m01 ~]# ansible web01 -m firewalld -a 'service=http state=enabled'

#允许访问80端口,临时生效
[root@m01 ~]# ansible web01 -m firewalld -a 'port=80/tcp state=enabled'

#配置允许10.0.0.0网段访问22端口
[root@m01 ~]# ansible web01 -m firewalld -a 'rich_rule="rule family=ipv4 source address=10.0.0.0/24 port port=22 protocol=tcp accept" state=enabled'

#配置网段白名单
[root@m01 ~]# ansible web01 -m firewalld -a 'source=10.0.0.0/24 zone=trusted state=enabled permanent=yes'
[root@m01 ~]# ansible web01 -m firewalld -a 'source=10.0.0.0/24 zone=trusted state=enabled permanent=no'
  • unarchive 解压模块

语法和参数

[root@m01 ~]# ansible-doc unarchive
EXAMPLES:
- name: Extract foo.tgz into /var/lib/foo
  unarchive:
    src: foo.tgz
    dest: /var/lib/foo
    remote_src: no			#默认是no
    
src			#包的路径
dest		#解压后的目标路径
remote_src
	yes		#包在受控端服务器上
	no		#包在控制端服务器上

实例

#解压包到受控端,包在控制端上
[root@m01 ~]# ansible web01 -m unarchive -a 'src=/root/php.tar.gz dest=/tmp'

#在受控端解压包,包在受控端
[root@m01 ~]# ansible web01 -m unarchive -a 'src=/tmp/php.tar.gz dest=/tmp remote_src=yes'
  • archive 压缩模块

[root@m01 ~]# ansible-doc archive
EXAMPLES:
- name: Compress directory /path/to/foo/ into /path/to/foo.tgz
  archive:
    path: /path/to/foo				#要打包的内容
    dest: /path/to/foo.tgz			#打好的包与存放位置
    format:gz					  #打包的类型 bz2, gz, tar, xz, zip

#打包实例
[root@m01 ~]# ansible web01 -m archive -a 'path=/tmp dest=/opt/php.tar.gz'
  • setup 模块 Ansible 主机信息模块

#1.获取web01主机所有信息
[root@m01 ~]# ansible web01 -m setup

#2.获取主机IP
[root@m01 ~]# ansible web01 -m setup -a 'filter=ansible_default_ipv4'

#3.获取主机名
[root@m01 ~]# ansible web01 -m setup -a 'filter=ansible_fqdn'
web01 | SUCCESS => {
    "ansible_facts": {
        "ansible_fqdn": "www.baidu.com", 
        "discovered_interpreter_python": "/usr/bin/python"
    }, 
    "changed": false    #false错误的
}

#4.获取内存信息
[root@m01 ~]# ansible web01 -m setup -a 'filter=ansible_memory_mb'
web01 | SUCCESS => {
    "ansible_facts": {
        "ansible_memory_mb": {
            "nocache": {
                "free": 720, 
                "used": 252
            }, 
            "real": {        
                "free": 276,       #free 空闲
                "total": 972, 	   #total 总数
                "used": 696
            }, 
            "swap": {
                "cached": 0, 
                "free": 1023, 
                "total": 1023, 
                "used": 0
            }
        }, 
        "discovered_interpreter_python": "/usr/bin/python"
    }, 
    "changed": false
}

#5.常用参数
ansible_all_ipv4_addresses:仅显示ipv4的信息。
ansible_devices:仅显示磁盘设备信息。
ansible_distribution:显示是什么系统,例:centos,suse等。
ansible_distribution_major_version:显示是系统主版本。
ansible_distribution_version:仅显示系统版本。
ansible_machine:显示系统类型,例:32位,还是64位。
ansible_eth0:仅显示eth0的信息。
ansible_hostname:仅显示主机名(不准确)
ansible_fqdn:仅显示主机名。
ansible_kernel:仅显示内核版本。
ansible_lvm:显示lvm相关信息。
ansible_memtotal_mb:显示系统总内存。
ansible_memfree_mb:显示可用系统内存。
ansible_memory_mb:详细显示内存情况。
ansible_swaptotal_mb:显示总的swap内存。
ansible_swapfree_mb:显示swap内存的可用内存。
ansible_mounts:显示系统磁盘挂载情况。
ansible_processor:显示cpu个数(具体显示每个cpu的型号)。
ansible_processor_vcpus:显示cpu个数(只显示总的个数)

Ansible ad-hoc实践

使用模块加ad-hoc搭建交作业页面

  • 准备httpd配置文件
[root@m01 ~]# yum install -y httpd
[root@m01 ~]# vim /etc/httpd/conf/httpd.conf
User www
Group www
  • 准备php安装包
[root@m01 ~]# ll
-rw-r--r--  1 root root 19889622 Nov 22 15:52 php.tar.gz
  • 准备PHP配置文件
[root@m01 ~]# tar xf php.tar.gz -C /tmp/
[root@m01 tmp]# yum localinstall -y *.rpm
[root@m01 tmp]# vim /etc/php-fpm.d/www.conf
user = www
group = www
[root@m01 tmp]# vim /etc/php.ini
upload_max_filesize = 200M
post_max_size = 200M
  • 准备代码文件
[root@m01 ~]# ll kaoshi.zip 
-rw-r--r-- 1 root root 26995 Nov 22 16:47 kaoshi.zip
  • 编写ansible命令

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值