'How can I execute multiple commands using Salt Stack?

I tried to add:

 mypack:
   pkg:
     - installed
     - pkgs:
       - mercurial
       - git
   cmd.run:
       - name: 'mkdir -p /opt/mypack'
   cmd.run: 'hg pull -u -R /opt/mypack || hg clone -R /opt https://...'
   cmd.run: 'ln -s /opt/mypack/etc/init.d/xxx /etc/init.d/xxx'

But for some reason this the state seems to execute/install but the commands are not executed, or at least not all of them.

I need a solution to run multiple commands and to fail the deployment if any of these fails.

I know that I could write a bash script and include this bash script, but I was looking for a solution that would work with only the YAML file.



Solution 1:[1]

You want this:

cmd-test:
  cmd.run:
    - name: |
        mkdir /tmp/foo
        chown dan /tmp/foo
        chgrp www-data /tmp/foo
        chmod 2751 /tmp/foo
        touch /tmp/foo/bar

Or this, which I would prefer, where the script is downloaded from the master:

cmd-test:
  cmd.script:
    - source: salt://foo/bar.sh
    - cwd: /where/to/run
    - user: fred

Solution 2:[2]

In addition to the above (better) suggestions, you can do this:

cmd-test:
  cmd.run:
    - names: 
      - mkdir -p /opt/mypack
      - hg pull -u -R /opt/mypack || hg clone -R /opt https://...
      - ln -s /opt/mypack/etc/init.d/xxx /etc/init.d/xxx

For reasons I don't understand yet (I'm a Salt novice), the names are iterated in reverse order, so the commands are executed backwards.

Solution 3:[3]

You can do as Dan pointed out, using the pipe or a cmd.script state. But it should be noted that you have some syntax problems in your original post. Each new state needs a name arg, you can't just put the command after the colon:

mypack:
  pkg:
    - installed
    - pkgs:
      - mercurial
      - git
  cmd.run:
    - name: 'my first command'
  cmd.run:
    - name: 'my second command'

However, that actually may fail as well, because I don't think you can put multiple of the same state underneath a single ID. So you may have to split them out like this:

first:
  cmd.run:
    - name: 'my first command'

second:
  cmd.run:
    - name: 'my second command'

Solution 4:[4]

As one of the users pointed out above, this works in proper order (salt 3000.2)


install_borg:
    cmd.run:
        - names: 
            - cd /tmp
            - wget https://github.com/borgbackup/borg/releases/download/1.1.15/borg-linux64
            - mv borg-linux64 /usr/local/bin/borg
            - chmod u+x /usr/local/bin/borg
            - chown root:root /usr/local/bin/borg
            - ln -s /usr/local/bin/borg /usr/bin/borg
        - unless: test -f /usr/bin/borg

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Dan Garthwaite
Solution 2
Solution 3 Colton Myers
Solution 4 perfecto25