在saltstack中,我如何有条件地,迭代地(jinja)应用包含状态

时间:2015-09-18 15:48:40

标签: salt-stack jinja2

这看起来似乎很简单。但我可以告诉你,我已经绞尽脑汁待了几天。我已经阅读了很多文档,与人们一起坐在IRC上,并与同事交谈,此时我还没有得到我真正想到的答案。

我已经研究了几种可能的方法

  • 反应器
  • 业务流程转轮

我不喜欢这两个因为自上而下执行的必要性......它们似乎适合于编排多个节点状态,而不是单个节点中的工作流。

  • 自定义状态

这是我真正想避免的,因为这是一个重复的工作流程,我不想像这样构建自定义。如果我和队友一起沿着这条路走下去,那就太可容易了。

  • 要求/观看

这些没有重复应用状态或逻辑顺序/工作流程的概念(我知道)。

还有一些我不会提及的。

没有进一步的讨论,这就是我的困境。

目标:

  • Jenkins Master获得部署
  • 我们可以在进行部署时对其进行单元测试
  • 我们只在必要时重启tomcat
  • 我们可以基于每个包更新插件
  • 强调清洁直观清晰的盐配置

Jenkins部署非常简单。我们放入包裹和配置中,然后设置好。

单元测试更难。作为一个例子,我有这个状态文件。

动作/ version.sls:

# Hit's the jenkins CLI interface to check for version info
# This can be used to verify that jenkins is active and the version we want

# Import some info
{%- from 'jenkins/init.sls' import jenkins_home with context %}

# Install plugins in jenkins_plugins list
jenkins_version:
  cmd.run:
    - name: java -jar jenkins-cli.jar -s "http://127.0.0.1:8080" version
    - cwd: /var/lib/tomcat/webapps/ROOT/WEB-INF/
    - user: jenkins

actions.version基本上验证了jenkins是否正在运行且可查询。我们希望在几个点的构建过程中确保这一点。

示例... tomcat需要时间才能启动。我们不得不为重启操作添加延迟。如果您查看下面的start.sls,您可以看到该操作正在发生。请注意在init_delay上打开的错误:。

动作/ start.sls:

# Starts the tomcat service
tomcat_start:
  service.running:
    - name: tomcat
    - enable: True
    - full_restart: True
# Not functional atm see --> https://github.com/saltstack/salt/issues/20631
#    - init_delay: 120

# initiate a 120 second delay after any service start to let tomcat come up.
tomcat_wait:
  module.run:
    - name: test.sleep
    - length: 60

include:
  - jenkins.actions.version

现在我们通过执行actions.stop和actions.start来实现此重启功能。我们有这个actions.version状态,我们可以用它来验证系统是否已准备好继续使用jenkins特定的状态工作流。

我想做一些像这样的事情......

 Install Jenkins --> Grab yaml of plugins --> install plugins that need it

非常直接。

除了循环使用插件的yaml我使用的是Jinja 现在我无法调用并确保可以重复应用start.sls和version.sls状态。

我正在寻找,这是一个很好的方法。

这类似于jenkins.sls

{% set repo_username = "foo" -%}
{% set repo_password = "bar" -%}

include:
  - jenkins.actions.version
  - jenkins.actions.stop
  - jenkins.actions.start

# Install Jenkins
jenkins:
  pkg:
    - installed

# Import Jenkins Plugins as List, and Working Path
{%- from 'jenkins/init.sls' import jenkins_home with context %}
{%- import_yaml "jenkins/plugins.sls" as jenkins_plugins %}
{%- import_yaml "jenkins/custom-plugins.sls" as custom_plugins %}
# Grab updated package list
jenkins-contact-update-server:
  cmd.run:
    - name: curl -L http://updates.jenkins-ci.org/update-center.json | sed '1d;$d' > {{ jenkins_home }}/updates/default.json
    - unless: test -d {{ jenkins_home }}/updates/default.json
    - require:
      - pkg: jenkins
      - service: tomcat
# Install plugins in jenkins_plugins list
{% for plugin in jenkins_plugins %}
jenkins-plugin-{{ plugin }}:
  cmd.run:
    - name: java -jar jenkins-cli.jar -s "http://127.0.0.1:8080" install-plugin "{{ plugin }}"
    - unless: java -jar jenkins-cli.jar -s "http://127.0.0.1:8080" list-plugins | grep "{{ plugin }}"
    - cwd: /var/lib/tomcat/webapps/ROOT/WEB-INF/
    - user: jenkins
    - require:
      - pkg: jenkins
      - service: tomcat

这是我被困的地方。要求不会这样做。和列表 行动似乎没有在盐中线性安排。我需要 能够只是验证jenkins已经准备好了。我需要 能够在单个插件之后重启tomcat 迭代被添加。我需要能够做到这一点来满足 插件顺序中的依赖项。

      - sls: jenkins.actions.version
      - sls: jenkins.actions.stop
      - sls: jenkins.actions.start
#    This can't work for several reasons
#    - watch_in:
#      - sls: jenkins-safe-restart
{% endfor %}

# Install custom plugins in the custom_plugins list
{% for cust_plugin,cust_plugin_url in custom_plugins.iteritems() %}
# manually downloading the plugin, because jenkins-cli.jar doesn't seem to work direct to artifactory URLs.
download-plugin-{{ cust_plugin }}:
  cmd.run:
    - name: curl -o {{ cust_plugin }}.jpi -O "https://{{ repo_username }}:{{ repo_password }}@{{ cust_plugin_url }}"
    - unless: java -jar jenkins-cli.jar -s "http://127.0.0.1:8080" list-plugins | grep "{{ cust_plugin }}"
    - cwd: /tmp
    - user: jenkins
    - require:
      - pkg: jenkins
      - service: tomcat
# installing the plugin ( REQUIRES TOMCAT RESTART AFTER )
custom-plugin-{{ cust_plugin }}:
  cmd.run:
    - name: java -jar jenkins-cli.jar -s "http://127.0.0.1:8080" install-plugin /tmp/{{ cust_plugin }}.jpi
    - unless: java -jar jenkins-cli.jar -s "http://127.0.0.1:8080" list-plugins | grep "{{ cust_plugin }}"
    - cwd: /var/lib/tomcat/webapps/ROOT/WEB-INF/
    - user: jenkins
    - require:
      - pkg: jenkins
      - service: tomcat
{% endfor %}

4 个答案:

答案 0 :(得分:3)

如果不使用反应器,信标,尤其是在没有编写自己的python执行模块的情况下,你将无法实现这一目标。

  

Jenkins Master获得部署

使用函数install(...):在python中编写jenkins执行模块。在该函数中,您可以通过调用现有的执行模块或自己编写来管理任何依赖项。

  

我们可以在部署过程中对其进行单元测试

在jenkins模块的安装功能中,您将根据安装结果触发特定events

if not _run_deployment_phase(...):
    __salt__['event.send']('jenkins/install/error', {
            'finished': False,
            'message': "Something failed during the deployment!",
    })

你会map that event to reactor sls files并处理它。

  

我们只在必要时重启tomcat

编写一个tomcat模块。添加_is_up(...)函数,通过解析结果的tomcat日志来检查tomcat是否已启动。在状态模块中调用函数并添加mod_watch函数。

def mod_watch():
    # required dict to return
    return_dict = {
           "name": "Tomcat install",
           "changes": {}, 
           "result": False,
           "comment": "",
            }
    if __salt__["tomcat._is_up"]():
      return_dict["result"] = True
      return_dict["comment"] = "Tomcat is up."

    if __opts__["test"]:
        return_dict["result"] = None
        return_dict["comment"] = "comment here about what will change"
        return return_dict

    # execute changes now

    return return_dict

在状态文件中使用状态模块。

install tomcat:
  tomcat.install:
    - name: ...
    - user: ...
    ...

wait until tomcat is up:
  cmd.run:
    - name: ...
    - watch:
      - tomcat: install tomcat
  

我们可以基于每个包更新插件

向名为install_plugin的jenkins执行模块添加一个函数。查看pkg.install代码以复制接口。

  

非常强调良好的清洁直观清晰的盐配置

编写python执行模块,以实现简单且可维护的配置逻辑。在您自己的状态模块中使用该执行模块。内部状态文件调用您自己的状态模块,并为您喜欢的任何状态渲染器提供单独的配置。

答案 1 :(得分:0)

状态只按设计执行一次。如果需要多次执行相同的操作,则需要多个状态。此外,包含仅包含一次。

您应该将所有代码放入单个sls文件中,并通过jinja迭代生成状态,而不是所有这些包含/需要您正在做的事情。

如果您要做的是添加一堆插件,添加配置文件,然后最后重新启动,那么您应该按顺序执行所有操作,不要使用require,并使用listen或listen_in而不是看或看_in。

listen / listen_in导致在状态运行结束时触发的操作发生。它们与Ansible中的处理程序概念类似。

答案 2 :(得分:0)

这是一个很老的问题,但是如果您将Jenkins / tomcat的启动/停止过程更改为标准的init / systemd / windows服务(所有行为良好的服务都应如此),则可以使用service.running Jenkins服务,并将其添加到每个custom-plugin-{{cust_plugin}}状态。

require_in: 
  - svc: jenkins
watch_in: 
  - svc: jenkins

您可以继续将cmd.run模块与onchanges一起使用。您必须在每个custom-plugin-{{cust_plugin}}状态中添加onchanges_in :,但是您需要在on changes列表中至少包含一项,否则该命令将在每次状态运行时触发。

答案 3 :(得分:-1)

如果您使用require,则会导致盐重新排序您的状态。如果您希望状态按顺序运行,只需按照您希望它们运行的​​顺序编写它们。

Watch / watch_in也将重新订购您的州。如果您使用listen / listen_in,它会将触发的操作排队,以按状态运行结束时触发的顺序运行。

请参阅:

http://ryandlane.com/blog/2014/07/14/truly-ordered-execution-using-saltstack/ http://ryandlane.com/blog/2015/01/06/truly-ordered-execution-using-saltstack-part-2/