【问题标题】:Check if service exists with Ansible使用 Ansible 检查服务是否存在
【发布时间】:2015-07-31 10:49:48
【问题描述】:

我有一个 Ansible playbook,用于将 Java 应用程序部署为 init.d 守护进程。

作为 Ansible 和 Linux 的初学者,我无法根据主机的状态有条件地在主机上执行任务。

也就是说,我有一些主机已经存在服务并且正在运行,我想在做任何其他事情之前停止它。然后可能会有新的主机,它们还没有服务。所以我不能简单地使用service: name={{service_name}} state=stopped,因为这将在新主机上失败。

我怎样才能做到这一点?到目前为止,这是我所拥有的:

  - name: Check if Service Exists
    shell: "if chkconfig --list | grep -q my_service;   then echo true;   else echo false; fi;"
    register: service_exists

# This should only execute on hosts where the service is present
  - name: Stop Service
    service: name={{service_name}} state=stopped
    when: service_exists
    register: service_stopped

# This too
  - name: Remove Old App Folder
    command: rm -rf {{app_target_folder}}
    when: service_exists

# This should be executed on all hosts, but only after the service has stopped, if it was present
  - name: Unpack App Archive
    unarchive: src=../target/{{app_tar_name}} dest=/opt

【问题讨论】:

    标签: centos ansible ansible-playbook


    【解决方案1】:

    查看 service_facts 模块,Ansible 2.5 中的新模块。

    - name: Populate service facts
      service_facts:
    - debug:
        msg: Docker installed!
      when: "'docker' in services"
    

    【讨论】:

    • 这看起来很有希望,但它的输出似乎与预期的服务名称不一致,至少对于检查telnet.socket 服务而言,它在ansible_facts.services 中显示为telnet@0.service
    • 服务事实在 hostvars[$host]['services'] 下收集
    • 使用when: "'docker' in services" 确实会失败——收集到的事实使用全名(docker.service)而不是docker 进行索引。可能取决于平台,但至少在 CentOS 上,事实仅使用全名。
    • relevant module page 上有一条关于如何访问服务名称的重要说明,值得注意。考虑到这一点,我在 Ubuntu 上成功使用了:when: ansible_facts.services['service-name.service'] is defined
    • 看来 service_facts 有点“慢”,我更喜欢检查服务文件是否存在
    【解决方案2】:

    当然,我也可以只检查包装脚本是否存在于 /etc/init.d 中。所以这就是我最终的结果:

      - name: Check if Service Exists
        stat: path=/etc/init.d/{{service_name}}
        register: service_status
    
      - name: Stop Service
        service: name={{service_name}} state=stopped
        when: service_status.stat.exists
        register: service_stopped
    

    【讨论】:

    • 是的,我回避了ignore_errors,因为我害怕由于拼写错误等而出现误报。此外,我试图说服我的团队投资于自动化我们的配置管理,并且不希望首先让他们看起来像某种黑客行为。 :)
    • ansible 还在 v2.0 的服务模块中添加了 must_exist 标志,这将消除第一次检查的需要:docs.ansible.com/service_module.html
    • @RyanTuck 您链接的页面上没有列出must_exist 参数。 2.0 现已正式发布。
    • 这在 Mint 18.2 上只对我部分有效。我的一些 systemd 服务有初始化脚本,但不是全部,请注意并检查是否使用此方法
    • 进一步了解@darkwing 和@abzarak 的cmets:可以直接检查/etc/systemd/system/{{service_name}}.service,而不是检查初始化脚本包装器。许多较新的系统和软件包版本正在删除 SysVinit 包装脚本。
    【解决方案3】:

    我将Florian's answer 修改为仅使用service 命令的返回码(这适用于Mint 18.2)

    - name: Check if Logstash service exist
      shell: service logstash status 
      register: logstash_status
      failed_when: not(logstash_status.rc == 3 or logstash_status.rc == 0)
    
    - name: Check if Logstash service exist
      service:
        name: logstash
        state: stopped 
      when: logstash_status.rc == 0
    

    【讨论】:

      【解决方案4】:

      如果“服务”模块可以处理“无法识别的服务”错误,那就太好了。

      这是我的方法,使用service 命令而不是检查初始化脚本:

      - name: check for apache
        shell: "service apache2 status"
        register: _svc_apache
        failed_when: >
          _svc_apache.rc != 0 and ("unrecognized service" not in _svc_apache.stderr)
      
      - name: disable apache
        service: name=apache2 state=stopped enabled=no
        when: "_svc_apache.rc == 0"
      
      • 检查“服务状态”的退出代码,当输出包含“无法识别的服务”时接受退出代码0
      • 如果退出代码为 0,则安装该服务(停止或运行)

      【讨论】:

        【解决方案5】:

        systemd 的另一种方法 (from Jakuje):

        - name: Check if cups-browsed service exists
          command: systemctl cat cups-browsed
          check_mode: no
          register: cups_browsed_exists
          changed_when: False
          failed_when: cups_browsed_exists.rc not in [0, 1]
        
        - name: Stop cups-browsed service
          systemd:
            name: cups-browsed
            state: stopped 
          when: cups_browsed_exists.rc == 0
        

        【讨论】:

          【解决方案6】:

          这种只使用服务模块的方式对我们有用:

          - name: Disable *service_name*
            service:
              name: *service_name*
              enabled: no
              state: stopped
            register: service_command_output
            failed_when: >
              service_command_output|failed
              and 'unrecognized service' not in service_command_output.msg
              and 'Could not find the requested service' not in service_command_output.msg
          

          【讨论】:

            【解决方案7】:

            我的几分钱。与上述方法相同,但适用于 Kubernetes

            检查 kublete 服务是否正在运行

            - name: "Obtain state of kublet service"
              command: systemctl status kubelet.service
              register: kubelet_status
              failed_when: kubelet_status.rc > 3
            

            如果 kublet 服务未运行,则显示调试消息

            - debug:
                msg: "{{ kubelet_status.stdout }}"
              when: "'running' not in kubelet_status.stdout"
            

            【讨论】:

            • 不幸的是,如果服务不存在(这就是 OP 所要求的),这种方法将不起作用。使用您的代码,您仍然会收到 Unit kubelet.service could not be found 错误。
            • @jso 你是对的。此解决方案假定服务已安装在主机上,因为问题指出 “我有一些主机的服务已经存在并正在运行”,但当服务不存在时会失败。因此,我赞成您的评论:)
            猜你喜欢
            • 1970-01-01
            • 2010-11-03
            • 1970-01-01
            • 2012-04-22
            • 1970-01-01
            • 2023-01-24
            • 2017-04-16
            • 2014-12-12
            相关资源
            最近更新 更多