Ansible Playbooks高级使用

文件操作

文件创建

  • file

用于设置文件/链接/目录的属性,或者删除文件/链接/目录

### state如果是directory当目录不存在时会自动创建;如果是file当文件不存在时不会自动创建
- name: Create log dir
  file:
    path: "{{ item.src }}"
    state: directory
  with_items: "{{ log_dirs }}"
  when: is_metal | bool
  tags:
    - common-log

- name: Mask lxc-net systemd service
  file:
    src: /dev/null
    path: /etc/systemd/system/lxc-net.service
    state: link
  when:
    - ansible_service_mgr == 'systemd'
  tags:
    - lxc-files
    - lxc-net

修改文件

  • lineinfile

用于检测文件是否存在特殊行或者使用后端正则表达式来替换匹配到的特殊行

- name: Extra lxc config
  lineinfile:
    dest: "/var/lib/lxc/{{ inventory_hostname }}/config"
    line: "{{ item.split('=')[0] }} = {{ item.split('=', 1)[1] }}"
    insertafter: "^{{ item.split('=')[0] }}"
    backup: "true"
  with_items: "{{ extra_container_config | default([]) }}"
  delegate_to: "{{ physical_host }}"
  register: _ec
  when: not is_metal | bool
  tags:
    - common-lxc
  • replace

lineinfile的多行匹配版本,此模块会在文件中插入一段内容,并在内容开始和结束位置设置标签,后续可以使用标签可以对此块内容进行操作

### 在ml2_conf.ini文件的[ml2]和[ml2_type_vlan]字段之间插入一段内容
- name: Enable ovn in neutron-server
  replace:
    dest: "{{ node_config_directory }}/neutron-server/ml2_conf.ini"
    regexp: '\[ml2\][\S\s]*(?=\[ml2_type_vlan\])'
    replace: |+
      [ml2]
      type_drivers = local,flat,vlan,geneve
      tenant_network_types = geneve
      mechanism_drivers = ovn
      extension_drivers = port_security
      overlay_ip_version = 4

      [ml2_type_geneve]
      vni_ranges = 1:65536
      max_header_size = 38

      [ovn]
      ovn_nb_connection = tcp:{{ api_interface_address }}:{{ ovn_northdb_port }}
      ovn_sb_connection = tcp:{{ api_interface_address }}:{{ ovn_sourthdb_port }}
      ovn_l3_mode = False
      ovn_l3_scheduler = chance
      ovn_native_dhcp = True
      neutron_sync_mode = repair
    backup: yes
  when:
    - action == "deploy"
    - inventory_hostname in groups['network']
  notify:
    - Restart neutron-server container
  • ini_file

ini后缀格式文件修改

### 设置l3_agent.ini文件[DEFAULT]字段的external_network_bridge选项值为br-ex
- name: Set the external network bridge
  vars:
      agent: "{{ 'neutron-vpnaas-agent' if enable_neutron_vpnaas | bool else 'neutron-l3-agent' }}"
  ini_file:
      dest: "{{ node_config_directory }}/{{ agent }}/l3_agent.ini"
      section: "DEFAULT"
      option: "external_network_bridge"
      value: "{{ neutron_bridge_name | default('br-ex') }}"
      backup: yes
  when:
      - action == "deploy"
      - inventory_hostname in ovn_central_address
  delegate_to: "{{ item }}"
  with_items: "{{ groups['neutron-server'] }}"
  notify:
      - Restart {{ agent }} container
  • assemble

将多个文件聚合成一个文件

### 将/etc/haproxy/conf.d目录下的文件内容聚合成/etc/haproxy/haproxy.cfg文件
- name: Regenerate haproxy configuration
  assemble:
    src: "/etc/haproxy/conf.d"
    dest: "/etc/haproxy/haproxy.cfg"
  notify: Restart haproxy
  tags:
    - haproxy-general-config

循环控制

  • with_items

标准循环,用于执行重复任务,{{ item }}类似宏展开

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

嵌套循环

### 修改neutron-server组所有主机的ml2_conf.ini文件的对应字段值
- name: Enable ovn in neutron-server
  vars:
    params:
      - { section: 'ml2', option: 'type_drivers', value: 'local,flat,vlan,geneve' }
      - { section: 'ml2', option: 'tenant_network_types', value: 'geneve' }
      - { section: 'ml2', option: 'mechanism_drivers', value: 'ovn' }
      - { section: 'ml2', option: 'extension_drivers', value: 'port_security' }
      - { section: 'ml2', option: 'overlay_ip_version', value: '4' }
      - { section: 'securitygroup', option: 'enable_security_group', value: 'True' }
  ini_file:
    dest: "{{ node_config_directory }}/neutron-server/ml2_conf.ini"
    section: "{{ item[0].section }}"
    option: "{{ item[0].option }}"
    value: "{{ item[0].value }}"
    backup: yes
  when:
    - action == "deploy"
    - inventory_hostname in ovn_central_address
  delegate_to: "{{ item[1] }}"
  with_nested:
    - "{{ params }}"
    - "{{ groups['neutron-server'] }}"
  notify:
    - Restart neutron-server container

流程控制

  • tags

设置任务标签

tasks:
    - yum: name={{ item }} state=installed
      with_items:
         - httpd
         - memcached
      tags:
         - packages

    - template: src=templates/src.j2 dest=/etc/foo.conf
      tags:
         - configuration

### 执行playbook可以指定只执行标签对应任务或跳过标签对应任务
# ansible-playbook example.yml --tags "configuration,packages"
# ansible-playbook example.yml --skip-tags "notification"
  • fail_when

用来控制playbook退出

- name: Check if firewalld is installed
  command: rpm -q firewalld
  register: firewalld_check
  failed_when: firewalld_check.rc > 1
  when: ansible_os_family == 'RedHat'
  • pre_tasks/post_tasks

用来设置在执行roles模块之前和之后需要执行的任务

- name: Install the aodh components
  hosts: aodh_all
  gather_facts: "{{ gather_facts | default(True) }}"
  max_fail_percentage: 20
  user: root
  pre_tasks:
    - include: common-tasks/os-lxc-container-setup.yml
    - include: common-tasks/rabbitmq-vhost-user.yml
      static: no
      vars:
        user: "{{ aodh_rabbitmq_userid }}"
        password: "{{ aodh_rabbitmq_password }}"
        vhost: "{{ aodh_rabbitmq_vhost }}"
        _rabbitmq_host_group: "{{ aodh_rabbitmq_host_group }}"
      when:
        - inventory_hostname == groups['aodh_api'][0]
        - groups[aodh_rabbitmq_host_group] | length > 0
    - include: common-tasks/os-log-dir-setup.yml
      vars:
        log_dirs:
          - src: "/openstack/log/{{ inventory_hostname }}-aodh"
            dest: "/var/log/aodh"
    - include: common-tasks/mysql-db-user.yml
      static: no
      vars:
        user_name: "{{ aodh_galera_user }}"
        password: "{{ aodh_container_db_password }}"
        login_host: "{{ aodh_galera_address }}"
        db_name: "{{ aodh_galera_database }}"
      when: inventory_hostname == groups['aodh_all'][0]
    - include: common-tasks/package-cache-proxy.yml
  roles:
    - role: "os_aodh"
      aodh_venv_tag: "{{ openstack_release }}"
      aodh_venv_download_url: "{{ openstack_repo_url }}/venvs/{{ openstack_release }}/{{ ansible_distribution | lower }}/aodh-{{ openstack_release }}-{{ ansible_architecture | lower }}.tgz"
    - role: "openstack_openrc"
      tags:
        - openrc
    - role: "rsyslog_client"
      rsyslog_client_log_rotate_file: aodh_log_rotate
      rsyslog_client_log_dir: "/var/log/aodh"
      rsyslog_client_config_name: "99-aodh-rsyslog-client.conf"
      tags:
        - rsyslog
  vars:
    is_metal: "{{ properties.is_metal|default(false) }}"
    aodh_rabbitmq_userid: aodh
    aodh_rabbitmq_vhost: /aodh
    aodh_rabbitmq_servers: "{{ rabbitmq_servers }}"
    aodh_rabbitmq_port: "{{ rabbitmq_port }}"
    aodh_rabbitmq_use_ssl: "{{ rabbitmq_use_ssl }}"
  tags:
    - aodh

主机路由

  • delegate_to

可以将当前任务放到其他hosts上执行

### 这是一段在容器中执行的playbook的一部分,这时候需要检测容器所在的宿主机上的对应目录是否存在,这时候就需要用到委托来跳出当前容器到宿主机上执行当前任务
- name: Ensure mount directories exists
  file:
    path: "{{ item['mount_path'] }}"
    state: "directory"
  with_items:
    - "{{ lxc_default_bind_mounts | default([]) }}"
    - "{{ list_of_bind_mounts | default([]) }}"
  delegate_to: "{{ physical_host }}"
  when:
    - not is_metal | bool
  tags:
    - common-lxc
  • local_action

将任务放在ansible控制主机(运行ansible-playbook的主机)上执行

- name: Check if the git cache exists on deployment host
  local_action:
    module: stat
    path: "{{ repo_build_git_cache }}"
  register: _local_git_cache
  when: repo_build_git_cache is defined

用户和用户组控制

  • group

创建用户组

### 创建系统管理员组haproxy,present表示不存在创建,absent表示存在删除
- name: Create the haproxy system group
  group:
    name: "haproxy"
    state: "present"
    system: "yes"
  tags:
    - haproxy-group
  • user

创建用户

### 创建haproxy:haproxy用户,并创建home目录
- name: Create the haproxy system user
  user:
    name: "haproxy"
    group: "haproxy"
    comment: "haproxy user"
    shell: "/bin/false"
    system: "yes"
    createhome: "yes"
    home: "/var/lib/haproxy"
  tags:
    - haproxy-user

其他

  • authorized_key

添加用户的SSH认证key

- name: Create authorized keys file from host vars
  authorized_key:
    user: "{{ repo_service_user_name }}"
    key: "{{ hostvars[item]['repo_pubkey'] | b64decode }}"
  with_items: "{{ groups['repo_all'] }}"
  when: hostvars[item]['repo_pubkey'] is defined
  tags:
    - repo-key
    - repo-key-store
  • slurp

用来读取远程主机上文件内容是base64加密的文件

### 读取id_rsa.pub文件的内容,并设置到变量repo_pub中
- name: Get public key contents and store as var
  slurp:
    src: "{{ repo_service_home_folder }}/.ssh/id_rsa.pub"
  register: repo_pub
  changed_when: false
  tags:
    - repo-key
    - repo-key-create
  • uri

web访问,类似执行curl命令

- name: test proxy URL for connectivity
  uri:
    url: "{{ repo_pkg_cache_url }}/acng-report.html"
    method: "HEAD"
  register: proxy_check
  failed_when: false
  tags:
    - common-proxy
  • wait_for

等待一个端口变得可用或者等待一个文件变得可用

- name: Wait for container ssh
  wait_for:
    port: "22"
    delay: "{{ ssh_delay }}"
    search_regex: "OpenSSH"
    host: "{{ ansible_host }}"
  delegate_to: "{{ physical_host }}"
  register: ssh_wait_check
  until: ssh_wait_check | success
  retries: 3
  when:
    - (_mc is defined and _mc | changed) or (_ec is defined and _ec | changed)
    - not is_metal | bool
  tags:
    - common-lxc
  • command

执行shell命令

### ignore_errors为true表示命令执行出错也不会退出playbook
- name: Check if clean is needed
  command: docker exec openvswitch_vswitchd ovs-vsctl br-exists br-tun
  register: result
  ignore_errors: True

切换用户

### 使用become会先切换成apache用户,再执行command命令,默认become_user用户为root(如果你ansible配置的就是root用户的免密码登入那就不需要become了)
- name: Run a command as the apache user
  command: somecommand
  become: true
  become_user: apache

检测链表是否为空

### pip_wheel_install为链表变量
- name: Install wheel packages
  shell: cd /tmp/wheels && pip install {{ item }}*
  with_items:
    - "{{ pip_wheel_install | default([]) }}"
  when: pip_wheel_install > 0
posted @ 2017-10-14 11:45  银魔术师  阅读(6437)  评论(0编辑  收藏  举报