playbooks可以包含多个plays(就是多个hosts锻),这样就可以在多个group之间切换: 
 
- hosts: webservers 
 
  user: root 
 


  tasks: 
 


 xxxxxx 
 

- hosts: databases 
 
  ruser: root 
 
  sudo: yes 
 
  tasks: 
 
 xxxxxx 
 
 remote_user: 
 



hosts行可以是一个或者多个group或者host,使用冒号分割。 
 
user行是在远程机器执行命令的用户,你也可以给单个task指定执行用户,参数是remote_user. 
 
sudo行允许你在远程以另外一个用户执行命令,默认是root。你也可以在单个task中使用sudo,而非整个play,如果你的sudo是需要密码的,则在允许playbook时在命令行需要提供--ask-sudo-pass参数 
 



每个play可以包含多个tasks,task的执行是顺序的,一次一个。 
 
每个task应该有一个name,它会在运行playbook时输出。 
 


modules是幂等的,这意味着你可以多次执行他们,但结果是一样的。 
 


command和shell模块是唯一两个可以不用K/V模式参数的模块,command和shell模块是在意命令执行状态返回码的,shell: /usr/bin/somecommand || /bin/true 
 
如果action行的参数太长,则可以用空格分割开他们,你在var section下面建立的变量在action行也可以使用,name行也可以使用,格式是 "{{ xxx }}",这些变量在templates中也可以使用 
 



在一个基本的playbook中,所有的task都列在play下面,列表看起来有点过于长,其实我们可以使用include命令来解决 
 


handler是一系列的tasks,它和一般的task没有任何区别,它通过name被notify引用,在notify字段指定的task会引用handler定义的task,notify字段会在playbook的最后一个task之后被触发,而且只会被触发一次。 
 



开始的时候,你可能把所有的task都写在一个playbook中,但有时候你想重用一些模块,这时候就麻烦了。你可以把task文件切分成小的task文件,然后在一个文件中引用其他task文件。 
 


playbooks也可以include其他playbook,这时候其他的playbook会插入到当前位置。其实task、handlers、var都可以这样引用,这其实就是roles的功能。 
 



如果你想在多个play或者playbooks之间重用task列表,你可以使用include。例如: 
 
定义task:task/foo.yml 
 
--- 
 
# possibly saved as tasks/foo.yml 
 


- name: placeholder foo 
 
  command: /bin/foo 
 


- name: placeholder bar 
 
  command: /bin/bar 
 


在playbook通过include引用: 
 
tasks: 
 


  - include: tasks/foo.yml 
 


你甚至可以传输变量到include,在include的文件内部,变量使用{{ xxx }}来定义 
 
tasks: 
 
  - include: wordpress.yml wp_user=timmy 
 
  - include: wordpress.yml wp_user=alice 
 
  - include: wordpress.yml wp_user=bob 
 


在1.4版本之后,你还可以一次传输多个变量,使用列表或者字典 
 
tasks: 
 
 - { include: wordpress.yml, wp_user: timmy, ssh_keys: [ 'keys/one.txt', 'keys/two.txt' ] } 
 


在1.0开始,你也可以通过其他语法把变量传输进include包含的文件中 
 
tasks: 
 
  - include: wordpress.yml 
 
    vars: 
 
        wp_user: timmy 
 
        ssh_keys: 
 
          - keys/one.txt 
 
          - keys/two.txt 
 



include也可以用在handlers上,例如有个重启apache的handler 
 
handlers.yml: 
 
--- 
 
# this might be in a file like handlers/handlers.yml 
 
- name: restart apache 
 
  service: name=apache state=restarted 
 


然后在其他handler中引用: 
 
handlers: 
 
  - include: handlers/handlers.yml 
 




现在我们已经见识过task和handlers来组织我们的playbook,但那种才是最好的组织方式?那就是roles。roles可以按照已知的文件目录结构自动的加载vars、task、handles。如何在roles中使用自己的modules,和扩展task、handlers一样,你可以在同级目录下新建一个library目录
roles能够根据层次型的目录结构自动的加载变量、文件、tasks、handlers等等。roles将变量、文件、tasks、module放置在单独的目录中,然后通过include可以把它们快速的集结在一起。

 1  一般顶级目录是以roles命名
 2  在roles目录下会分部着各种功能角色的目录,就是使目标机器变成什么状态。例如:db、web等等
 3  在功能角色目录下分散着一系列目录,用来实现具体的实现步骤。这些目录就是playbook一般用到的资源,例如:files、handlers、tasks、templates、vars、meta、default、library等目录。用不到的功能可以不用创建相应的目录。
 4  最后一步,在总的playbook中通过include集结这些功能角色


 tasks:该目录必须包含一个main.yml文件,这个文件里面定义了该功能角色的tasks列表,是实现该功能角色的主要文件,可以用include来包含其他tasks文件
 handlers:该目录包含一个main.yml文件,定义该功能角色用到的handler。
 vars:该目录包含一个main.yml文件,用于定义该功能角色用到的变量,只对当前role有用
 meta:设定role和role直接的依赖关系,包含在main.yml文件中
 library:该功能角色自定义的模块
 files:任何copy tasks都可以从该目录中引用相关文件,而不用指定绝对路径,任何script tasks也可以从该目录中引用相关脚本,而不用指定绝对路径。其实就是copy和script引用文件的目录
 template:template模块会自动在该目录下寻找相关的jinja2模板
 default:为当前角色设定默认变量用到的目录,包含在mian.yml文件中site.yml
webservers.yml
fooservers.yml
roles/
   common/
     files/
     templates/
     tasks/
     handlers/
     vars/
     defaults/
     meta/
     library/
   webservers/
     files/
     templates/
     tasks/
     handlers/
     vars/
     defaults/
     meta/ 
 
在playbook中可以这样引用: 
 
---
- hosts: webservers
  roles:
     - common
     - webservers 
 
可以在配置文件的roles_path中设置role的搜索路径 
 


也可以给roles传输参数,例如: 
 
---
- hosts: webservers
  roles:
    - common
    - { role: foo_app_instance, dir: '/opt/a',  port: 5000 }
    - { role: foo_app_instance, dir: '/opt/b',  port: 5001 } 
 
 
你也可以指定task在role之前或者之后生效: 
 
- hosts: webservers

  pre_tasks:
    - shell: echo 'hello'

  roles:
    - { role: some_role }

  tasks:
    - shell: echo 'still busy'

  post_tasks:
    - shell: echo 'goodbye' 
 


变量的定义: 
 


在playbook中可以如下定义变量: 
 
- hosts: webservers 
 
  vars: 
 
    http_port: 80 
 


也可以从facts中获取信息,例如{{ ansible_devices.sda.model }} 
 
如果你不想知道你hosts上的facts信息,你可以关闭他们的收集: 
 
- hosts: whatever 
 
  gather_facts: no 
 


If a remotely managed system has an “/etc/ansible/facts.d” directory, any files in this directory ending in ”.fact”, can be JSON, INI, or executable files returning JSON, and these can supply local facts in Ansible. /etc/ansible/facts.d/preferences.fact 
 



命令行传变量 
 
ansible-playbook release.yml --extra-vars "hosts=vipers user=starbuck" 
 


Registered Variables: 
 
当你执行一个命令的时候,这个命令产生的结果可以保存到一个变量,这时候可以把这个结果从一个模块传输到另一个模块。 
 
- hosts: web_servers 
 


  tasks: 
 


     - shell: /usr/bin/foo 
 
       register: foo_result 
 
       ignore_errors: True 
 


     - shell: /usr/bin/bar 
 
       when: foo_result.rc == 5 
 




条件语句 
 
when: 
 
tasks: 
 
  - name: "shutdown Debian flavored systems" 
 
    command: /sbin/shutdown -t now 
 
    when: ansible_os_family == "Debian" 
 


tasks: 
 
  - command: /bin/false 
 
    register: result 
 
    ignore_errors: True 
 
  - command: /bin/something 
 
    when: result|failed 
 
  - command: /bin/something_else 
 
    when: result|success 
 
  - command: /bin/still/something_else 
 
    when: result|skipped 
 


with_items: 
 


role和include中的when: 
 
- hosts: webservers 
 
  roles: 
 
     - { role: debian_stock_config, when: ansible_os_family == 'Debian' } 
 


- include: tasks/sometasks.yml 
 
  when: "'reticulating splines' in output" 
 



Register Variables: 
 
- name: registered variable usage as a with_items list 
 
  hosts: all 
 
  tasks: 
 


      - name: retrieve the list of home directories 
 
        command: ls /home 
 
        register: home_dirs 
 


      - name: add home dirs to the backup spooler 
 
        file: path=/mnt/bkspool/{{ item }} src=/home/{{ item }} state=link 
 
        with_items: home_dirs.stdout_lines 
 
        # same as with_items: home_dirs.stdout.split() 
 




如何访问其他机器的变量: 
 
hostvars变量允许你查询另一个节点的变量,包括facts收集那台的数据。例如,你想用另一个节点的fact的数据:{{ hostvars['test.example.com'(节点)]['ansible_distribution'] }} 
 


group_names is a list (array) of all the groups the current host is in 
 
{% if 'webserver' in group_names %} 
 
   # some part of a configuration file that only applies to webservers 
 
{% endif %} 
 



groups is a list of all the groups (and hosts) in the inventory. This can be used to enumerate all hosts within a group 
 
{% for host in groups['app_servers'] %} 
 
   # something that applies to all app servers. 
 
{% endfor %} 
 


loops: 
 
- name: add several users 
 
  user: name={{ item }} state=present groups=wheel 
 
  with_items: 
 
     - testuser1 
 
     - testuser2 
 


- name: add several users 
 
  user: name={{ item.name }} state=present groups={{ item.groups }} 
 
  with_items: 
 
    - { name: 'testuser1', groups: 'wheel' } 
 
    - { name: 'testuser2', groups: 'root' } 
 




lookup_plugins主要是用来实现扩展playbook里面各种的字符串和变量的扩展 
 


print json.dumps({"web":{"hosts":["10.10.10.66"],"vars":{"todo":"this server whill restart"}},"nginx":{"hosts":["10.10.10.69"],"va 
 
rs":{"todo":"this nginx is restart"}}}) 
 


ansible inventory的返回格式,web相当于/etc/ansible/hosts里面的[web]标题,hosts相当于[web]下面的主机list,vars相当于变量。 
 


ansible -i /xxx/xxx.py group -m xxx -a xxx 
 



Callbacks 是一个有趣的插件类型,允许ansible响应事件的时候调用额外的callback插件 
 
范例:https://github.com/ansible/ansible/blob/devel/plugins/callbacks/log_plays.py 
 


/opt/ansible/lib/ansible/module_utils 
 



如果有用sudo,切sudo有密码,则需要加上以下参数 
 
ansible-playbook  -i ./hosts --ask-sudo-pass test.yml