ansible入门
Ansible是一个配置管理和配置工具,使用SSH连接到服务器并运行配置好的任务,服务器上不需要安装任何其他软件,只需要开启SSH,客户端的ansible会完成所有其他的工作。

首先安装Ansible:
apt-get安装的版本很低,建议使用pip安装:
sudo pip install ansible
可能会提示什么:from pip import main ImportError: cannot import name main
那就使用--user:pip install --user ansible

在虚拟环境virtualenv中安装:

sudo pip install -U virtualenv # 首先安装virtualenv
# 然后进入一个ansible专门的文件夹,创建虚拟环境:
virtualenv .venv
source .venv/bin/activate
# 进入了虚拟环境
pip install ansible

pip install -U ansible # 任何时候都可以这样更新ansible
1
2
3
4
5
6
7
8
配置ansible:
在ansible1里面,我们需要用到/etc/ansible里面的默认配置,但是像上面那样在虚拟环境里面安装ansible,那么我们完全不需要这些默认文件,我们可以在非本地路径下创建这些配置文件。

管理服务器:Inventory
我们需要创建一个inventory file用来定义管理哪个server,命名随意,一般为hosts:

[web]
192.168.22.10
192.168.22.11
1
2
3
在web标签下我们需要管理两个server

当我们在server上运行ansible against本地机,我们不需要关心Inventory file里面的内容
当我们本地运行ansible against远程服务器时,Inventory file需要这样编写:

[local]
127.0.0.1

[remote]
192.168.1.2
1
2
3
4
5
接下来是建立本地与远程服务器之间连接的命令。


Running Commands
接下来我们针对服务器运行任务tasks,ansible是通过SSH去管理服务器的:

# Run against localhost
ansible -i ./hosts --connection=local local -m ping

# Run against remote server针对远程服务器运行ansible
ansible -i ./hosts remote -m ping
1
2
3
4
5
参数说明

--connection=local的意思是不需要通过ssh连接,因为我们针对的就是本地,还可以是--connection=ssh意思是需要ssh连接。
-i ./hosts指定Inventory file,告诉我们连接到哪里
remote,local,all指明使用哪个标签下面的服务器清单,all表示针对每个服务器运行
-m ping表示使用ping模块,会返回ping结果
然后针对阿里云服务器进行了尝试,运行ansible -i ./hosts remote -m ping发现报错:

39.107.74.200 | UNREACHABLE! => {
"changed": false,
"msg": "Failed to connect to the host via ssh: Permission denied (publickey,password).",
"unreachable": true
}
1
2
3
4
5
感觉问题应该是这样的命令没有输入用户名和密码,尝试
ansible -i ./hosts remote -m ping -u root --ask-pass 前提是使用sudo apt-get安装好了sshpass,然后返回结果:

39.107.74.200 | SUCCESS => {
"changed": false,
"ping": "pong"
}
1
2
3
4
但是每次敲这么多命令就很复杂,更简单的方法是将用户名密码写入hosts文件里面:

[remotr]
29.107.74.200 ansible_ssh_user=root ansible_ssh_pass=123456
1
2
然后就不需要额外的命令了


Modules
ansible使用模块来完成任务,比如安装软件,复制文件以及使用模板。
模块aret the way to use absible, 因为模块可以使用上下文来确定完成任务需要做些什么。
如果没有模块,我们只能运行shell命令,其实是使用的shell模块:

ansible -i ./hosts remote -b --become-user=root all
-m shell -a 'apt-get install nginx’
1
2
-b 成为另一个用户
--become-user=root 以用户root运行命令
-m定义模块,这里使用的是shell模块
-a给模块传递参数
这样做并不好,因为这样只能完成bash脚本能够完成的任务


我们还可以使用apt模块,这样能确保幂等(一个幂等操作的特点是其任意多次执行所产生的影响均与一次执行的影响相同)

ansible -i ./hosts remote -b --become-user=root
-m apt -a 'name=nginx state=installed update_cache=true'
1
2
如果执行后显示的是change:False,就表明已经安装,没有对环境造成任何影响

name=nginx表示需要安装的软件包名
state=installed表示需要的结束状态
update_cache=true表示是否更新软件包储存库缓存
通过模块我们可以做我们想做的事,但是为了更好管理,我们把任务都放到playbook里面,就可以运行多个tasks


Playbooks
playbook可以运行多任务还有一些高级功能,playbook和roles(剧本和角色)都使用YAML文件定义:
nginx.yml

- hosts: remote
become: yes
become_user: root
tasks:
- name: install nginx
apt:
name: nginx
state: present
update_cache: true
1
2
3
4
5
6
7
8
9
YAML文件格式:用缩排方式呈现,结构通过缩进来表示,连续的项目使用-表示,键值对用:表示,不可以使用TAB.
如何使用playbook呢?直接运行:
ansible-playbook -i ./hosts nginx.yml


Handlers
handlers=tasks,处理程序可以做任务可以完成的任何事,但是只有当另一个task调用它的时候才会执行。
我们添加notify指令到上面的playbook中:

- hosts: remote
become: yes
become_user: root
tasks:
- name: Install Nginx
apt:
name: nginx
state: present
update_cache: true
notify:
- Start Nginx
handlers:
- name: Start Nginx
service:
name: nginx
state: started
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
任务task运行后会通知名为start Nginx的处理程序:该handler处理使用服务service模块,可以启动停止重启等操作。

所以handler和task的唯一区别就是task会自动调用,handler得等着task来调用它

这里还有一个地方需要注意:如果这里nginx已经安装,那么nginx安装任务不会运行,handler也不会被调用。

使用变量:
首先定义变量:

- hosts: local
connection: local
become: yes
become_user: root
vars:
- docroot: /var/www/serversforhackers.com/public
1
2
3
4
5
6
使用变量方法:

file:
path: '{{ docroot }}'
1
2
使用Jinja模板,必须是单引号或者双引号


roles(最终使用方法,比playbook更好配置)
roles角色用于组织多个task并封装成完成这些任务需要的数据,但是真实的配置场景里面,我们需要很多变量,文件,模板之类的东西,虽然可以配合playbook使用,但是roles更好,因为它有一个目录结构来规范

roles
rolename
- files
- handlers
- meta
- templates
- tasks
- vars
1
2
3
4
5
6
7
8
我们下面创建一个新的role例子,role的任务有:

1. Add Nginx Repository- 使用apt_repository模块添加Nginx稳定PPA以获取最新的稳定版本的Nginx 。
2. Install Nginx - 使用Apt模块安装Nginx。
3. Create Web Root - 最后创建一个Web根目录。
1
2
3
在每一个子目录中,ansible都会自动找到并读取那个叫main.yml的文件。

创建角色
进入本地ansible-test文件夹,激活虚拟环境:

mkdir nginx # 这里最好就使用roles这个名字
cd nginx
ansible-galaxy init nginx
1
2
3
然后进入nginx,会发现整个role目录已经建立好了。

1. files
里面放置我们需要复制到服务器中的文件


2. handlers
记得放在main.yml文件中:

---
- name: Start Nginx
service:
name: nginx
state: started

- name: Reload Nginx
service:
name: nginx
state: reloaded
1
2
3
4
5
6
7
8
9
10
前面提到了handler需要被task调用才起作用,我们可以在其他的YAML文件中调用它们


3. meta
这个目录里面的main.yml用于描述角色之间的依赖关系,比如nginx role依赖于ssl role,那么:

---
dependencies:
- {role: ssl}
1
2
3
这样调用nginx角色时,自动会先调用ssl角色
如果无任何依赖:
dependencies: []


4. Template
这里面不需要有main.yml文件,这里的文件使用的是Jinja2模板引擎的.j2文件
比如我们新建一个文件为serversforhackers.com.conf.j2:

server {
# Enforce the use of HTTPS
listen 80 default_server;
server_name {{ domain }};
return 301 https://$server_name$request_uri;
}

server {
listen 443 ssl default_server;

root /var/www/{{ domain }}/public;
index index.html index.htm index.php;

access_log /var/log/nginx/{{ domain }}.log;
error_log /var/log/nginx/{{ domain }}-error.log error;

server_name {{ domain }};

charset utf-8;

include h5bp/basic.conf;

ssl_certificate {{ ssl_crt }};
ssl_certificate_key {{ ssl_key }};
include h5bp/directive-only/ssl.conf;

location / {
try_files $uri $uri/ /index.php$is_args$args;
}

location = /favicon.ico { log_not_found off; access_log off; }
location = /robots.txt { log_not_found off; access_log off; }

location ~ \.php$ {
include snippets/fastcgi.conf;
fastcgi_pass unix:/var/run/php7.1-fpm.sock;
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
这是一个标准的php应用的Nginx配置文件,里面有一些变量


5. vars
该目录需要有main.yml文件:

---
domain: serversforhackers.com
ssl_key: /etc/ssl/sfh/sfh.key
ssl_crt: /etc/ssl/sfh/sfh.crt
1
2
3
4

6. tasks
这个是最重要的文件夹,使用role的时候,运行的文件就是该文件夹下面的main.yml文件:

---
- name: Add Nginx Repository
apt_repository:
repo: ppa:nginx/stable
state: present

- name: Install Nginx
apt:
pkg: nginx
state: installed
update_cache: true
notify:
- Start Nginx

- name: Add H5BP Config
copy:
src: h5bp
dest: /etc/nginx
owner: root
group: root
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
运行角色 Run Role
我们要对服务器运行一个或者多个role的时候,我们还是需要用到playbook,playbook需要和roles在同一个目录下面,然后创建一个主yml文件,在这个文件里面定义需要使用的角色以及是对哪个服务器执行的操作:
新建 server.yml(这就是那个playbook):

- hosts: local
connection: local
roles:
- nginx
1
2
3
4
然后老样子运行playbook:
ansible-playbook -i ./hosts server.yml

前面几大板块的关系:
playbook >> roles >> tasks+handler+… >>modules
总的playbook里面可能就几行,所有各部分的功能交给不同的role来完成。
每个role里面是各种task并且调用handler支撑功能的。
每个task和handler里面的功能是由各种模块modules实现的。


我们使用ssh与托管节点(服务器)通信,默认使用sftp(使用SSH协议进行FTP传输的协议叫做SFTP,),如果不可用,需要在ansible.cfg文件中配置成scp方式

这里不建议使用virtualenv虚拟环境来安装ansible

Inventory文件
对于每一个host可以选择连接类型和连接用户名:

[targets]

localhost ansible_connection=local
39.107.74.200 ansible_connection=ssh ansible_ssh_user=root
1
2
3
4
给整个组添加变量
上面是给服务器单独配置变量,但是也可以给整个组配置变量:

[remote:vars]
ansible_connection=ssh

[remote]
host1
host2
1
2
3
4
5
6
只要需要配置的组的名字对上了,就可以获取配置

将一个组变成另一个组的成员:

[groupA]
host1

[groupB:children]
groupA
1
2
3
4
5
各种参数说明:

参数 说明
ansible_ssh_host 远程主机名
ansible_ssh_port ssh端口
ansible_ssh_user ssh用户名
ansible_ssh_pass ssh密码,建议使用–ask-pass
ansible_sudo_pass sudo 密码,建议使用–ask-sudo-pass
ansible_connection 与远程主机连接类型local ssh
ansible_python_interpreter 目标主机python路径,适用于主机有多个python

Ad-Hoc
ansible 有两种方法完成任务,一个是as-hoc,一个是playbook,前者解决简单任务,后者复杂任务

Ansible配置文件
ansible的一些设置可以通过配置文件完成,大多数情况下,默认配置就足够了,配置被读取的顺序:

ANSIBLE_CONFIG(环境变量)
ansible.cfg(当前目录)
.ansible.cfg(当前家目录)
/etc/ansible/ansible.cfg
1
2
3
4
下面是配置文件不同段的详解:
多数为默认段,[defaults]中

代码 说明
ask_pass 控制playbook是否弹出询问密码,默认值为No
ask_sudo_pass 是否弹出询问sudo密码
command_warnings 当shell和命令行模块被默认模块简化的时,是否发出警告
deprecation_warnings 设置为True,允许在输出结果中禁用‘不建议使用’警告
forks 设置与主机通信时默认并行进程数,如果有很多主机,高数值会让跨主机行为更快,设置为100
gathering 控制默认facts收集(远程系统变量),smart值代表没有facts的新host不会被扫描,在节省facts收集时比较有用
inventory 默认库文件(hosts文件)位置
library 默认模块的位置,library = ./library/,但是ansible知道如何搜寻多个用冒号隔开的路径,也会搜索playbook中的./library
log_path ansible将会在选定位置记录执行信息
module_lang 默认模块和计算机通信语言,默认为C语言
module_name 是默认模块名,默认为command,但是不支持shell变量等,所以可能希望改为shell
nocolor=0 为输出结果加上颜色,便于区分,如果想关闭设置为1
remote_port 默认的远程端口,默认为22
remote_tmp 使用默认路径希望像更换补丁一样使用模块
remote_user 默认远程主机用户名
roles_path 指的是’roles/’下的额外目录,用于playbook搜索Ansible roles.
timeout ssh尝试超时时间
host_key_checking 检测主机秘钥,禁用设为False
[ssh_connection] 调整ssh通信连接

代码 说明
scp_if_ssh 设置为True,scp将代替用来为远程主机传输文件,没必要修改
pipelining 开启将显著提高性能,在不通过实际文件传输的情况下执行ansible模块来使用管道特性,从而减少执行远程模块SSH操作次数

Ansible Playbook
1. 主机和用户:

---
- hosts: webservers
remote_user: yourname
sudo: yes
1
2
3
4
还可以sudo到不同的用户身份:
sudo_user: postgres


2. Tasks列表:
modules具有幂等性,如果再一次执行module,module只会执行必ansible_ssh_connection=ssh要的改动,所以重复多次执行playbook也没有问题。

基本task定义,使用key=value格式,大多数都是这样的:

tasks:
- name: make sure apache is running
service: name=httpd state=running
1
2
3
特别的模块是command和shell,不使用key=value:

tasks:
- name: run this command and ignore the result
shell: /usr/bin/somecommand
ignore_errors: True
1
2
3
4
action中可以使用变量,假设前面vars里面设置了变量’vhost‘

tasks:
- name: create a virtual host file for {{ vhost }}
template: src=somefile.j2 dest=/etc/httpd/conf.d/{{ vhost }}
1
2
3

3. Handlers 在发生改变的时候执行操作
因为module具有幂等性,如果远端系统被人改动,可以重放playbook达到恢复的目的,playbook本身有识别这种改动的功能,有一个基本的event system时间系统可以响应改动

- name: template configuration file
template: src=template.j2 dest=/etc/foo.conf
notify:
- restart memcached
- restart apache
handlers:
- name: restart memcached
service: name=memcached state=restarted
- name: restart apache
service: name=apache state=restarted
1
2
3
4
5
6
7
8
9
10
notify会在playbook每一个task结束的时候触发,即使有多个不同的task通知改动发生,notify也只会触发一次

handlers一般用于重启服务,此外很少用到


4. 执行一个playbook:
ansible-playbook playbook.yml -f 10
并行的级别为10

5. include file
在一个playbook中,include指令可以跟普通的task混合在一起使用:

tasks:

- include: tasks/a.yml
- include: tasks/b.yml
1
2
3
4
如果希望定义一个重启服务的handler,只需要定义一次,可以创建一个handlers.yml文件

---
# this might be in a file like handlers/handlers.yml
- name: restart apache
service: name=apache state=restarted
1
2
3
4
然后在主playbook中:

handlers:
- include: handlers/handlers.yml
1
2
我们可以定义一个顶层playbook:

- name: this is a play at the top level of a file
hosts: all
remote_user: root

tasks:

- name: say hi
tags: foo
shell: echo "hi..."

- include: load_balancers.yml
- include: webservers.yml
- include: dbservers.yml
1
2
3
4
5
6
7
8
9
10
11
12
13

Variables:
1. 在playbook中直接定义变量:

- hosts: webservers
vars:
http_port: 80
1
2
3
2. YAML陷阱,开头使用变量

- hosts: app_servers
vars:
app_path: {{ base_path }}/22
1
2
3
这样是不行的,以变量开头需要将整行用双引号包起来。

app_path: "{{ base_path }}/22"
1
3. 变量单独放到一个文件:

---
- hosts: all
remote_user: root
vars:
favcolor: blue
vars_files:
- /vars/external_vars.yml
1
2
3
4
5
6
7
变量文件:

---
somevar: somevalue
password: magic
1
2
3

条件选择:
when语句:

tasks:
- shell: echo "only on Red Hat 6, derivatives, and later"
when: ansible_os_family == "RedHat" and ansible_lsb.major_release|int >= 6
1
2
3
在特定情况下运行task

- name: add several users
user: name={{ item }} state=present groups=wheel
with_items:
- testuser1
- testuser2
1
2
3
4
5

Roles
roles会自动加载tasks,handler
创建roles:

mkdir nginx # 这里最好就使用roles这个名字
cd nginx
ansible-galaxy init nginx
1
2
3
调用roles的方式:

---
- hosts: webservers
roles:
- common
- webservers
1
2
3
4
5
如果 roles/x/tasks/main.yml 存在, 其中列出的 tasks 将被添加到 play 中
如果 roles/x/handlers/main.yml 存在, 其中列出的 handlers 将被添加到 play 中
如果 roles/x/vars/main.yml 存在, 其中列出的 variables 将被添加到 play 中
如果 roles/x/meta/main.yml 存在, 其中列出的 “角色依赖” 将被添加到 roles 列表中 (1.3 and later)
所有 copy tasks 可以引用 roles/x/files/ 中的文件,不需要指明文件的路径。
所有 script tasks 可以引用 roles/x/files/ 中的脚本,不需要指明文件的路径。
所有 template tasks 可以引用 roles/x/templates/ 中的文件,不需要指明文件的路径。
所有 include tasks 可以引用 roles/x/tasks/ 中的文件,不需要指明文件的路径。

最后的项目结构应该是:

production # inventory file for production servers 关于生产环境服务器的清单文件
stage # inventory file for stage environment 关于 stage 环境的清单文件

group_vars/
group1 # here we assign variables to particular groups 这里我们给特定的组赋值
group2 # ""
host_vars/
hostname1 # if systems need specific variables, put them here 如果系统需要特定的变量,把它们放置在这里.
hostname2 # ""

library/ # if any custom modules, put them here (optional) 如果有自定义的模块,放在这里(可选)
filter_plugins/ # if any custom filter plugins, put them here (optional) 如果有自定义的过滤插件,放在这里(可选)

site.yml # master playbook 主 playbook
webservers.yml # playbook for webserver tier Web 服务器的 playbook
dbservers.yml # playbook for dbserver tier 数据库服务器的 playbook

roles/
common/ # this hierarchy represents a "role" 这里的结构代表了一个 "role"
tasks/ #
main.yml # <-- tasks file can include smaller files if warranted
handlers/ #
main.yml # <-- handlers file
templates/ # <-- files for use with the template resource
ntp.conf.j2 # <------- templates end in .j2
files/ #
bar.txt # <-- files for use with the copy resource
foo.sh # <-- script files for use with the script resource
vars/ #
main.yml # <-- variables associated with this role
defaults/ #
main.yml # <-- default lower priority variables for this role
meta/ #
main.yml # <-- role dependencies

webtier/ # same kind of structure as "common" was above, done for the webtier role
monitoring/ # ""
fooapp/ # ""

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39

Ansible常用模块
1. ping
检查指定节点机器是否能联通

2. yum
这个模块是RedHat和CentOS作为远端节点的OS的时候,用得最多的包管理工具

3. apt
这个模块是ubuntu和Debian作为远端节点的时候用的最多的包管理工具

deb: 软件包名字,可选
install_recommends: 默认为true,设置为False代表只下载不安装
update_cache: yes相当于apt-get update
name: apt要下载的软件名,指定版本可用name=git=1.6
state: (present, adsent, latest) present表示为安装,然后是删除,在是安装位最新版本
4. pip
安装python库依赖项,必须参数为name或者requirements

chdir: 执行pip前需要进入的目录
name: 库名字
requirements: requirements.txt文件路径,应该是远程系统的本地文件,就可以使用chdir将文件指定为相对定位
version: 库版本
extra_args: pip额外参数
executable: 显式可执行文件或可执行文件的路径名
virtualenv: 要安装到的virtualenv路径名
virtualenv_command: 创建虚拟环境
virtualenv_python: 用于创建虚拟环境的命令或路径名
state:(present, lastest, absent)
5. synchronize
使用rsync同步文件,将主控方目录推送到指定节点的目录下

delete: 删除不存在的文件
src: 要同步到目的地的源主机的路径
dest: 目的地上同步地址
dest_port: 目的地机上的端口
mode: push/pull,默认push,本机向远程传文件
rsync_opts:
6. copy
在远程主机上面复制文件

src: 复制到远程的文件在本地的地址,如果路径以/结尾,只复制目录里面的内容,如果没有,则包含目录在内的整个内容全部复制
content: 代替src,可以直接设定指定文件的值
dest: 复制到远程文件的路径
directory_mode: 目录权限
force:默认为yes,强制覆盖
others: 所有file模块里面的选项
mode: 0644
7. user

home:指定用户家目录,需要配合createhome使用
groups: 指定用户组
uid:
password: 用户密码,不能使用明文密码
name: 指定用户名
createhome: 是否创建家目录,yes、no
system: 是否为系统用户
remove: 当state为absent的时候,remove=yes表示联同家目录一起删除
state: present, absent
shell: 指定用户的shell环境
generate_ssh_key: 生成ssh秘钥
ssh_key_bits: 指定创建ssh秘钥中的位数
ssh_key_passphrase: ssh秘钥密码
ssh_key_file: ssh秘钥文件
ssh_key_type: ssh秘钥类型
8. group

gid: 指定的gid
name: 指定用户名
state: present, absent
system: true,表示创建的是系统组
9. service

arguments: 命令选项
enabled: 是否开机启动 yes
name: 必选,服务名称
runlevel: 运行级别
sleep: restarted之间的间隔
state: started/stopped/restarted/reloaded
10. get_url
用于从http,ftp,https服务器上面上下载文件,类似wget

sha256sum: 下载后sha256验证
timeout: 下载超时时间,默认为10s
url: 下载的url
url_password, url_username: 如果下载需要提供验证
dest: 下载到哪里
headers: 以key:value的格式自定义http标头
11. file
用于远程主机上面的文件操作

force: 强制创建软连接
group: 文件目录的属组
mode: 文件目录的权限
owner: 文件目录的属主
path: 必选,文件目录的路径
recurse: 递归的设置文件的属性
src: 被连接的源文件路径,当state=link的时候
dest: 被连接到的路径,当state=link的时候
state: directory 如果目录不存在则创建目录
file 如果文件不存在则创建
link 创建软连接
hard 创建硬链接
touch 如果文件不存在则创建,如果存在则修改最后修改时间属性
absent 删除文件目录或者取消连接文件
# 创建一个目录,如果它不存在
- file:
path: /etc/some_directory
state: directory
mode: 0755
1
2
3
4
5
12. unarchive
解压文件

copy: 解压文件之前,是否现将文件复制到远程主机
creates: 指定一个文件名,当该文件存在,解压不执行
dest: 远程主机上解压文件的绝对路径
list_files: yes会列出压缩包里面的文件
mode: 解压后文件的权限
src: 如果copy为yes,需要指定压缩文件的原路径
group: 解压后文件属组
owner: 解压后文件的属主
13. shell

chdir: 运行命令前切换到此目录
将阿里云API封装成ansible module例子:
#!/usr/bin/env python
#coding=utf-8
from ansible.module_utils.basic import AnsibleModule
from aliyunsdkcore.client import AcsClient
from aliyunsdkcore.request import CommonRequest

def run_ecs_instance(accessKey, accessSecret, region, ImageId, InstanceType, SecurityGroupId, VSwitchId,
InternetMaxBandwidthOut, HostName, Password, InternetChargeType, SystemDisk_Size, SystemDisk_Category, Amount, InstanceChargeType, ZoneId):
client = AcsClient(accessKey, accessSecret, region)

request = CommonRequest()
request.set_accept_format('json')
request.set_domain('ecs.aliyuncs.com')
request.set_method('POST')
request.set_protocol_type('https') # https | http
request.set_version('2014-05-26')
request.set_action_name('RunInstances')

request.add_query_param('RegionId', region)
request.add_query_param('ImageId', ImageId)
request.add_query_param('InstanceType', InstanceType)
request.add_query_param('SecurityGroupId', SecurityGroupId)
request.add_query_param('VSwitchId', VSwitchId)
request.add_query_param('InternetMaxBandwidthOut', InternetMaxBandwidthOut)
request.add_query_param('HostName', HostName)
request.add_query_param('Password', Password)
request.add_query_param('InternetChargeType', InternetChargeType)
request.add_query_param('SystemDisk.Size', SystemDisk_Size)
request.add_query_param('SystemDisk.Category', SystemDisk_Category)
request.add_query_param('Amount', Amount)
request.add_query_param('InstanceChargeType', InstanceChargeType)
request.add_query_param('ZoneId', ZoneId)

response = client.do_action(request)
# python2: print(response)
print(str(response, encoding = 'utf-8'))
return response

def ansible_module_builder():
#
module_args = dict(
action = dict(type='str', required=True),
accessKey = dict(type='str', required=True),
accessSecret = dict(type='str', required=True),
region = dict(type='str', required=True),
ImageId = dict(type='str', required=True),
InstanceType = dict(type='str', required=True),
SecurityGroupId = dict(type='str', required=True),
VSwitchId = dict(type='str', required=True),
InternetMaxBandwidthOut = dict(type='int', required=True),
HostName = dict(type='str', required=True),
Password = dict(type='str', required=True),
InternetChargeType = dict(type='str', required=True),
SystemDisk_Size = dict(type='int', required=True),
SystemDisk_Category = dict(type='str', required=True),
Amount = dict(type='int', required=True),
InstanceChargeType = dict(type='str', required=True),
ZoneId = dict(type='str', required=True)
)

module = AnsibleModule(
argument_spec = module_args,
supports_check_mode = True,
)

if module.params['action'] == 'createEcsInstance':
result = run_ecs_instance(
module.params['accessKey'],
module.params['accessSecret'],
module.params['region'],
module.params['ImageId'],
module.params['InstanceType'],
module.params['SecurityGroupId'],
module.params['VSwitchId'],
module.params['InternetMaxBandwidthOut'],
module.params['HostName'],
module.params['Password'],
module.params['InternetChargeType'],
module.params['SystemDisk_Size'],
module.params['SystemDisk_Category'],
module.params['Amount'],
module.params['InstanceChargeType'],
module.params['ZoneId']
)
module.exit_json(**result)

def main():
ansible_module_builder()

if __name__ == '__main__':
main()
————————————————

原文链接:https://blog.csdn.net/qq_43355223/article/details/88111875

螃蟹在剥我的壳,笔记本在写我,漫天的我落在枫叶上雪花上,而你在想我。 --章怀柔