Detect host operating system distro in chef-solo deploy bash script - linux

When deploying a chef-solo setup you need to switch between using sudo or not eg:
bash install.sh
and
sudo bash install.sh
Depending on the distro on the host server. How can this be automated?

ohai already populates these attributes and are readily available in your recipe
for example,
"platform": "centos",
"platform_version": "6.4",
"platform_family": "rhel",
you can reference to these as
if node[:platform_family].include?("rhel")
...
end
To see what other attributes ohai sets, just type
ohai
on the command line.

You can detect the distro on the remote host and deploy accordingly. in deploy.sh:
DISTRO=`ssh -o 'StrictHostKeyChecking no' ${host} 'bash -s' < bootstrap.sh`
The DISTRO variable is populated by whatever is echoed by the bootstrap.sh script, which is run on the host machine. So we can now use bootstrap.sh to detect the distro or any other server settings we need to and echo, which will be bubbled to the local script and you can respond accordingly.
example deploy.sh:
#!/bin/bash
# Usage: ./deploy.sh [host]
host="${1}"
if [ -z "$host" ]; then
echo "Please provide a host - eg: ./deploy root#my-server.com"
exit 1
fi
echo "deploying to ${host}"
# The host key might change when we instantiate a new VM, so
# we remove (-R) the old host key from known_hosts
ssh-keygen -R "${host#*#}" 2> /dev/null
# rough test for what distro the server is on
DISTRO=`ssh -o 'StrictHostKeyChecking no' ${host} 'bash -s' < bootstrap.sh`
if [ "$DISTRO" == "FED" ]; then
echo "Detected a Fedora, RHEL, CentOS distro on host"
tar cjh . | ssh -o 'StrictHostKeyChecking no' "$host" '
rm -rf /tmp/chef &&
mkdir /tmp/chef &&
cd /tmp/chef &&
tar xj &&
bash install.sh'
elif [ "$DISTRO" == "DEB" ]; then
echo "Detected a Debian, Ubuntu distro on host"
tar cj . | ssh -o 'StrictHostKeyChecking no' "$host" '
sudo rm -rf ~/chef &&
mkdir ~/chef &&
cd ~/chef &&
tar xj &&
sudo bash install.sh'
fi
example bootstrap.sh:
#!/bin/bash
# Fedora/RHEL/CentOS distro
if [ -f /etc/redhat-release ]; then
echo "FED"
# Debian/Ubuntu
elif [ -r /lib/lsb/init-functions ]; then
echo "DEB"
fi
This will allow you to detect the platform very early in the deploy process.

Related

OpenBSD 6.7 how to install xbase

I am updating our integration test environments to OpenBSD 6.7 (from 6.5)
We use ansible to install all the packages on the target system (openbsd 6.7, Vagrant image https://app.vagrantup.com/generic/boxes/openbsd6/versions/3.0.6 )
With the above image, I cannot install java openjdk 11.
obsd-31# pkg_add -r jdk%11
quirks-3.325 signed on 2020-05-27T12:56:02Z
jdk-11.0.7.10.2p0v0:lz4-1.9.2p0: ok
jdk-11.0.7.10.2p0v0:zstd-1.4.4p1: ok
jdk-11.0.7.10.2p0v0:jpeg-2.0.4p0v0: ok
jdk-11.0.7.10.2p0v0:tiff-4.1.0: ok
jdk-11.0.7.10.2p0v0:lcms2-2.9p0: ok
jdk-11.0.7.10.2p0v0:png-1.6.37: ok
jdk-11.0.7.10.2p0v0:giflib-5.1.6: ok
Can't install jdk-11.0.7.10.2p0v0 because of libraries
|library X11.17.0 not found
| not found anywhere
|library Xext.13.0 not found
| not found anywhere
|library Xi.12.1 not found
| not found anywhere
|library Xrender.6.0 not found
| not found anywhere
|library Xtst.11.0 not found
| not found anywhere
|library freetype.30.0 not found
| not found anywhere
Direct dependencies for jdk-11.0.7.10.2p0v0 resolve to png-1.6.37 libiconv-1.16p0 giflib-5.1.6 lcms2-2.9p0 jpeg-2.0.4p0v0
Full dependency tree is giflib-5.1.6 lz4-1.9.2p0 tiff-4.1.0 png-1.6.37 xz-5.2.5 jpeg-2.0.4p0v0 lcms2-2.9p0 zstd-1.4.4p1 libiconv-1.16p0
Couldn't install jdk-11.0.7.10.2p0v0
my guess is that xbase is not installed.
However, I cannot figure out how to install xbase without rebooting into a bootable installer (because I need to do it via a shell command running from ansible)
Is there a way?
The generic OpenBSD Vagrant image you're using was created as a command line environment, so the X windows files were were excluded during the install process.
There are lots of ways to add X windows to OpenBSD after installation, but the quickest method that comes to mind would be:
sudo su -l
curl -LO 'https://ftp.usa.openbsd.org/pub/OpenBSD/6.7/amd64/x{base,serv,font,share}67.tgz'
tar xzf xbase67.tgz -C /
tar xzf xserv67.tgz -C /
tar xzf xfont67.tgz -C /
tar xzf xshare67.tgz -C /
rm -f xbase67.tgz xfont67.tgz xserv67.tgz xshare67.tgz
ldconfig /usr/local/lib /usr/X11R6/lib
If you would like to test for the presence of X windows on OpenBSD, try using the following shell snippet:
if [ -d /usr/X11R6/bin/ ] && [ -f /usr/X11R6/bin/xinit ]; then
echo "X windows has been installed."
else
echo "This is a command line only system."
fi
The xbase file set can be extracted manually via the following commands:
cd /
curl -LO https://ftp.usa.openbsd.org/pub/OpenBSD/6.7/amd64/xbase67.tgz
tar xzvf xbase67.tgz
Note: this is the mirror used in the vagrant sources.
If you care about security enough to use OpenBSD, then you really shouldn't grab new package sets from the internet without also checking the hashes/signatures are valid. Try this script:
#!/bin/ksh
echo -n "Downloading ... "
curl --silent --fail --fail-early -O "https://ftp.usa.openbsd.org/pub/OpenBSD/7.0/amd64/SHA256.sig" -O "https://ftp.usa.openbsd.org/pub/OpenBSD/7.0/amd64/x{base,font,serv,share}70.tgz"
if [ $? != 0 ]; then
echo "X windows download failed. Terminating."
exit 1
fi
echo "complete."
signify -Cp /etc/signify/openbsd-70-base.pub -x SHA256.sig xbase70.tgz xfont70.tgz xserv70.tgz xshare70.tgz
if [ $? != 0 ]; then
echo "X windows signature verification failed. Terminating."
exit 1
fi
tar -z -x -C / -f xbase70.tgz && tar -z -x -C / -f xfont70.tgz && tar -z -x -C / -f xserv70.tgz && tar -z -x -C / -f xshare70.tgz
if [ $? != 0 ]; then
echo "X windows installation failed. Terminating."
exit 1
fi
echo "Installation complete. Happy hacking."
On the other hand if you just want a one liners:
# Install just x11 base set.
sudo ksh -c 'curl --silent https://ftp.usa.openbsd.org/pub/OpenBSD/7.0/amd64/xbase70.tgz | gzip -d -c | tar -x -C / -f - '
# Install all the x11 sets.
sudo ksh -c 'curl --silent https://ftp.usa.openbsd.org/pub/OpenBSD/7.0/amd64/xbase70.tgz | gzip -d -c | tar -x -C /-f - '
You can omit the sudo portion if you are already logged in as root. And for the vagrant folks, the lazy version looks:
# Install just x11 base set from the host, to a vagrant guest.
vagrant ssh -c "sudo ksh -c 'curl --silent https://ftp.usa.openbsd.org/pub/OpenBSD/7.0/amd64/xbase70.tgz | gzip -d -c | tar -x -C / -f - '"
# Install all the x11 sets from the host, to a vagrant guest.
vagrant ssh -c "sudo ksh -c 'curl --silent -O \"https://ftp.usa.openbsd.org/pub/OpenBSD/7.0/amd64/x{base,font,serv,share}70.tgz\" && tar -z -x -C / -f xbase70.tgz && tar -z -x -C / -f xfont70.tgz && tar -z -x -C / -f xserv70.tgz && tar -z -x -C / -f xshare70.tgz'"

Running OpenSSH in an Alpine Docker Container

I've installed OpenSSH and now I wish to run it as described in the documentation by running /etc/init.d/sshd start. However it does not start:
/ # /etc/init.d/sshd start
/bin/ash: /etc/init.d/sshd: not found
Thoughts?
P.S.
/ # ls -la /etc/init.d/sshd
-rwxr-xr-x 1 root root 2622 Jan 14 20:48 /etc/init.d/sshd
Contents of /etc/init.d/sshd:
#!/sbin/openrc-run
# Copyright 1999-2015 Gentoo Foundation
# Distributed under the terms of the GNU General Public License v2
# $Header: /var/cvsroot/gentoo-x86/net-misc/openssh/files/sshd.rc6.4,v 1.5 2015/05/04 02:56:25 vapier Exp $
description="OpenBSD Secure Shell server"
description_checkconfig="Verify configuration file"
description_reload="Reload configuration"
extra_commands="checkconfig"
extra_started_commands="reload"
: ${SSHD_CONFDIR:=/etc/ssh}
: ${SSHD_CONFIG:=${SSHD_CONFDIR}/sshd_config}
: ${SSHD_PIDFILE:=/var/run/${SVCNAME}.pid}
: ${SSHD_BINARY:=/usr/sbin/sshd}
depend() {
use logger dns
if [ "${rc_need+set}" = "set" ] ; then
: # Do nothing, the user has explicitly set rc_need
else
local x warn_addr
for x in $(awk '/^ListenAddress/{ print $2 }' "$SSHD_CONFIG" 2>/dev/null) ; do
case "${x}" in
0.0.0.0|0.0.0.0:*) ;;
::|\[::\]*) ;;
*) warn_addr="${warn_addr} ${x}" ;;
esac
done
if [ -n "${warn_addr}" ] ; then
need net
ewarn "You are binding an interface in ListenAddress statement in your sshd_config!"
ewarn "You must add rc_need=\"net.FOO\" to your /etc/conf.d/sshd"
ewarn "where FOO is the interface(s) providing the following address(es):"
ewarn "${warn_addr}"
fi
fi
}
checkconfig() {
if [ ! -d /var/empty ] ; then
mkdir -p /var/empty || return 1
fi
if [ ! -e "${SSHD_CONFIG}" ] ; then
eerror "You need an ${SSHD_CONFIG} file to run sshd"
eerror "There is a sample file in /usr/share/doc/openssh"
return 1
fi
if ! yesno "${SSHD_DISABLE_KEYGEN}"; then
ssh-keygen -A || return 1
fi
[ "${SSHD_PIDFILE}" != "/var/run/sshd.pid" ] \
&& SSHD_OPTS="${SSHD_OPTS} -o PidFile=${SSHD_PIDFILE}"
[ "${SSHD_CONFIG}" != "/etc/ssh/sshd_config" ] \
&& SSHD_OPTS="${SSHD_OPTS} -f ${SSHD_CONFIG}"
"${SSHD_BINARY}" -t ${SSHD_OPTS} || return 1
}
start() {
checkconfig || return 1
ebegin "Starting ${SVCNAME}"
start-stop-daemon --start --exec "${SSHD_BINARY}" \
--pidfile "${SSHD_PIDFILE}" \
-- ${SSHD_OPTS}
eend $?
}
stop() {
if [ "${RC_CMD}" = "restart" ] ; then
checkconfig || return 1
fi
ebegin "Stopping ${SVCNAME}"
start-stop-daemon --stop --exec "${SSHD_BINARY}" \
--pidfile "${SSHD_PIDFILE}" --quiet
eend $?
if [ "$RC_RUNLEVEL" = "shutdown" ]; then
_sshd_pids=$(pgrep "${SSHD_BINARY##*/}")
if [ -n "$_sshd_pids" ]; then
ebegin "Shutting down ssh connections"
kill -TERM $_sshd_pids >/dev/null 2>&1
eend 0
fi
fi
}
reload() {
checkconfig || return 1
ebegin "Reloading ${SVCNAME}"
start-stop-daemon --signal HUP \
--exec "${SSHD_BINARY}" --pidfile "${SSHD_PIDFILE}"
eend $?
}
A container is not a full installed environment.
The official document is for that installed alpine on some machine.
With power on, boot up services, etc. that a container does not have.
So, anything in /etc/init.d/ can not be used directly in a container which is used by boot up service (like systemd, or alpine's rc*). That's why you got error messages cause the rc* isn't installed in the container.
What you need to do is start sshd manuanlly.
You can take look on below example:
https://hub.docker.com/r/danielguerra/alpine-sshd/~/dockerfile/
Despite there are some details still not clear to me, let me take a voice in the discussion. The solution specified by the below configuration works for me. It's the result of arduous experiments.
First, the dockerfile
FROM alpine
RUN apk update && \
apk add --no-cache sudo bash openrc openssh
RUN mkdir -p /run/openrc && \
touch /run/openrc/softlevel && \
rc-update add sshd default
RUN adduser --disabled-password regusr && \
sh -c 'echo "regusr:<encoded_passwd>"' | chpasswd -e > /dev/null 2>&1 && \
sh -c 'echo "regusr ALL=NOPASSWD: ALL"' >> /etc/sudoers
VOLUME ["/home/reguser/solution/entrypoint-init.d","/sys/fs/cgroup"]
USER reguser
WORKDIR /home/reguser
RUN mkdir -p $HOME/solution && sudo chown reguser:reguser $HOME/solution
ADD ./entrypoint.sh /home/reguser/solution/
EXPOSE 22
ENTRYPOINT ["./solution/entrypoint.sh"]
CMD ["/bin/bash"]
Next, /home/reguser/solution/entrypoint.sh
#!/bin/bash
for f in ./solution/entrypoint-init.d/*; do
case "$f" in
*.sh) echo "$0: running $f"; . "$f" ;;
*) echo "$0: ignoring $f" ;;
esac
echo
done
exec "$#"
Next, /home/reguser/solution/entrypoint-init.d/10-ssh-up.sh
#!/bin/bash
sudo sed --in-place --expression='/^#[[:space:]]*Port[[:space:]]\+22$/ s/^#//i' -- /etc/ssh/sshd_config
sudo sed --in-place --expression='/^#[[:space:]]*AddressFamily[[:space:]]\+any$/ s/^#//i' -- /etc/ssh/sshd_config
sudo sed --in-place --expression='/^#[[:space:]]*HostKey[[:space:]]\+\/etc\/ssh\/ssh_host_rsa_key$/ s/^#//i' -- /etc/ssh/sshd_config
sudo sed --in-place --expression='/^#[[:space:]]*HostbasedAuthentication[[:space:]].*/ s/^#//i' -- /etc/ssh/sshd_config
sudo sed --in-place --expression='/^[[:space:]]*HostbasedAuthentication[[:space:]].*/ s/^[[:space:]]*\(HostbasedAuthentication\)[[:space:]]\(.*\)/\1 no/i' -- /etc/ssh/sshd_config
sudo sed --in-place --expression='/^[[:space:]]*HostbasedAuthentication[[:space:]]\+yes.*/ s/^/#/i' -- /etc/ssh/sshd_config
sudo sed --in-place --expression='/^#[[:space:]]*IgnoreRhosts[[:space:]].*/ s/^#//i' -- /etc/ssh/sshd_config
sudo sed --in-place --expression='/^[[:space:]]*IgnoreRhosts[[:space:]].*/ s/^[[:space:]]*\(IgnoreRhosts\)[[:space:]]\(.*\)/\1 yes/i' -- /etc/ssh/sshd_config
sudo sed --in-place --expression='/^[[:space:]]*IgnoreRhosts[[:space:]]\+no.*/ s/^/#/i' -- /etc/ssh/sshd_config
sudo sed --in-place --expression='/^#[[:space:]]*PasswordAuthentication[[:space:]].*/ s/^#//i' -- /etc/ssh/sshd_config
sudo sed --in-place --expression='/^[[:space:]]*PasswordAuthentication[[:space:]].*/ s/^[[:space:]]*\(PasswordAuthentication\)[[:space:]]\(.*\)/\1 yes/i' -- /etc/ssh/sshd_config
sudo sed --in-place --expression='/^[[:space:]]*PasswordAuthentication[[:space:]]\+no.*/ s/^/#/i' -- /etc/ssh/sshd_config
sudo sed --in-place --expression='/^#[[:space:]]*PubkeyAuthentication[[:space:]].*/ s/^#//i' -- /etc/ssh/sshd_config
sudo sed --in-place --expression='/^[[:space:]]*PubkeyAuthentication[[:space:]].*/ s/^[[:space:]]*\(PubkeyAuthentication\)[[:space:]]\(.*\)/\1 yes/i' -- /etc/ssh/sshd_config
sudo sed --in-place --expression='/^[[:space:]]*PubkeyAuthentication[[:space:]]\+no.*/ s/^/#/i' -- /etc/ssh/sshd_config
sudo sed --in-place --expression='/^#[[:space:]]*PrintMotd[[:space:]].*/ s/^#//i' -- /etc/ssh/sshd_config
sudo sed --in-place --expression='/^[[:space:]]*PrintMotd[[:space:]].*/ s/^[[:space:]]*\(PrintMOTD\)[[:space:]]\(.*\)/\1 no/i' -- /etc/ssh/sshd_config
sudo sed --in-place --expression='/^[[:space:]]*PrintMotd[[:space:]]\+yes.*/ s/^/#/i' -- /etc/ssh/sshd_config
sudo sed --in-place --expression='$ a\' --expression='\nAcceptEnv LANG LC_\*' -- /etc/ssh/sshd_config
sudo /etc/init.d/sshd --dry-run start
sudo /etc/init.d/sshd start
The last two lines are in the heart of the trick. In particular, the sudo /etc/init.d/sshd --dry-run start makes the solution working.
Finally, command-line controls
docker build --tag='dockerRegUser/sshdImg:0.0.1' --file='./dockerfile' .
docker container create --tty \
--volume $(pwd)/dock/entrypoint-init.d:/home/reguser/solution/entrypoint-init.d:ro \
--name sshdCnt 'dockerRegUser/sshdImg:0.0.1' tail -f /dev/null
docker start sshdCnt && \
ssh-keygen -f "/home/user/.ssh/known_hosts" -R "$(docker inspect --format '{{ .NetworkSettings.IPAddress }}' sshdCnt)" && \
sleep 5 && \
ssh-copy-id -i ~/.ssh/sshkey reguser#$(docker inspect --format '{{ .NetworkSettings.IPAddress }}' sshdCnt)
I know, I know, there is a lot of unnecessary constructs. The example is also against the single service docker container principle. But there are phases and situations in solution development and delivery lifecycle that justify (or at least tempt) considering extending the container with the sshd or other openrc-controlled services.
/etc/init.d/sshd: not found
Try to run these commands:
apk add --no-cache openrc
rc-update add sshd
Check first is sshd is not present in /usr/bin or /usr/sbin.
Then, init.d should have sshd only if you set it up to to automatically start wiht:
rc-update add sshd
rc-status
I needed sshd for a very specific reason. I had to run front (cypress) and back (django) end tests on a CI server. Running them in one container is tricky at the least, so I decided to go with 2 containers. Also, there had to be one entrypoint that will run tests in both containers. So, the idea was that one container will run its tests, than run the tests in the other container over ssh.
In your case, you might not want to do exactly as I did, e.g. setting empty root password, empty passphrase.
It's best to run it in a separate directory, since it creates files (id_rsa.pub).
server.sh:
#!/bin/sh -eux
apk add openssh-server
ssh-keygen -A
passwd -d root
mkdir ~/.ssh
while ! [ -e id_rsa.pub ]; do sleep 1; done
cp id_rsa.pub ~/.ssh/authorized_keys
/usr/sbin/sshd -De
client.sh:
#!/bin/sh -eux
apk add openssh-client wait4ports
ssh-keygen -f ~/.ssh/id_rsa -N ''
cp ~/.ssh/id_rsa.pub .
wait4ports -s 1 tcp://c1:22
ssh-keyscan -t rsa c1 > ~/.ssh/known_hosts
ssh c1 echo DO SOMETHING
echo done
docker-compose.yml:
version: '3'
services:
server:
image: alpine:3.12
command: sh -c 'cd app && ./server.sh'
volumes:
- .:/app
client:
image: alpine:3.12
command: sh -c 'cd app && ./client.sh'
volumes:
- .:/app
$ docker-compose up -d && docker-compose logs -f
If you decide to run it again:
$ rm -f id_rsa.pub && docker-compose down && docker-compose up -d && docker-compose logs -f
If you want to setup openssh server on your docker container with alpine try this Dockerfile.
In this example, I am using docker:dind image
FROM docker:dind
# Setup SSH Service
RUN \
apk update && \
apk add openrc --no-cache && \
apk add openssh-server && \
rc-update add sshd && \
rc-status && \
touch /run/openrc/softlevel
# Expose port for ssh
EXPOSE 22
# Start SSH Service
CMD ["sh" , "-c", "service sshd restart && sh"]
Once your container is up and running try running this command to make sure ssh works fine:
ssh localhost

Bash script creating hybrid iso generates “unexpected end of file”

I've created a simple bash script that creates a hybrid iso. But when I try to run it, I get the output:
hybridiso.sh: line 58: syntax error: unexpected end of file.
I've checked the script and tried to makes changes to it but I still get the same output. What's wrong with the script?
#!/bin/bash
##Sanity Cheks##
if [ "$(whoami)" != root ]; then
echo "You must be root to execute this script."
fi
if [ ! -x /usr/bin/xorriso ]; then
echo "xorriso is not installed. Run 'apt-get install xorriso' to install it."
exit 1
fi
if [ ! -x /usr/bin/live-build ]; then
echo "live-build is not installed. Run 'apt-get install live-build' to install it."
exit 1
fi
if [ ! -x /usr/bin/syslinux ]; then
echo "syslinux is not insatlled. Run 'apt-get install syslinux' to install it."
exit 1
fi
if [ ! -x /usr/bin/mksquashfs ]; then
echo "squashfs-tools is not installed. Run 'apt-get install squashfs-tools' to install it."
exit 1
fi
###############
mkdir $PWD/hybridiso
cd hybridiso
mkdir -p binary/live && mkdir -p binary/isolinux
read -e -p "Enter local file path for linux kernel " kernel
read -e -p "Enter local file path for initrd " initrd
cp $kernel binary/live/ && cp $initrd binary/live/
#mksquashfs chroot binary/live/filesystem.squashfs -comp xz -e boot
cp /usr/lib/syslinux/isolinux.bin binary/isolinux/
cp /usr/lib/syslinux/menu.c32 binary/isolinux/
while true; do
read -p "Do you have an isolinux.cfg? " resp
if [ $resp -eq no ]; then
echo "You need to create a valid isolinux.cfg file!"
echo "Creating example file $PWD/isolinux.cfg.example"
echo -e "ui menu.c32\nprompt 0\nmenu title Boot Menu\ntimeout 300\n\n\nlabel live-amd64\n menu label ^Live (amd64)\n menu default\n linux /live/linux\n append initrd=/live/initrd.gz boot=live persistence quiet\n\n\nlabel live-amd64-failsafe\n menu label ^Live (amd64 failsafe)\nlinux /live/linux\nappend initrd=/live/initrd.gz boot=live persistence config memtest noapic noapm nodma nomce nolapic nomodest nosmp nosplash vga=normal\n\n\nendtext" >> isolinux.cfg.example
exit 1
elif [ $resp -eq yes ]; then
break
else
"Put only in yes or no"
fi
read -e -p "Enter local file path for isolinux.cfg" isolinux
cp $isolinux binary/isolinux/
xorriso -as mkisofs -r -J -joliet-long -l -cache-inodes -isohybrid-mbr /usr/lib/syslinux/isohdpfx.bin -partition_offset 16 -A "Debian Live" -b isolinux/isolinux.bin -c isolinux/boot.cat -no-emul-boot -boot-load-size 4 -boot-info-table -o kiosk.iso binary
echo "Script is succesfull!"
exit 0
You haven't terminated the while loop with done anywhere; Add done at the appropriate location.

shell script ssh command not working

I have a small list of servers, and I am trying to add a user on each of these servers. I can ssh individually to each server and run the command.
sudo /usr/sbin/useradd -c "Arun" -d /home/amurug -e 2014-12-12 -g users -u 1470 amurug
I wrote a script to loop through the list and run this command but I get some errors.
#!/bin/bash
read -p "Enter server list: " file
if [[ $file == *linux* ]]; then
for i in `cat $file`
do
echo "creating amurug on" $i
ssh $i sudo /usr/sbin/useradd -c "Arun" -d /home/amurug -e 2014-12-12 -g users -u 1470 amurug
echo "==============================================="
sleep 5
done
fi
When I run the script it does not execute the command.
creating amurug on svr102
Usage: useradd [options] LOGIN
Options:
What is wrong with my ssh crommand in my script?
Try this script:
#!/bin/bash
read -p "Enter server list: " file
if [[ "$file" == *linux* ]]; then
while read -r server
do
echo "creating amurug on" "$server"
ssh -t -t "$server" "sudo /usr/sbin/useradd -c Arun -d /home/amurug \
-e 2014-12-12 -g users -u 1470 amurug"
echo "==============================================="
sleep 5
done < "$file"
fi
As per man bash:
-t
Force pseudo-tty allocation. This can be used to execute arbitrary screen-based programs on a remote which can be very useful, e.g. when implementing menu services. Multiple -t options force tty allocation, even if ssh has no local tty.

Bash reading from file and parsing each line [duplicate]

This question already has an answer here:
Loop only iterates once with `ssh` in the body [duplicate]
(1 answer)
Closed 8 years ago.
I need to manage updates of a particular software on several customers' linux servers. The updates are provided by sending .tar.gz files to each server and inflating it overwriting the old software files.
I've put the customers' server list in a txt file like this:
user1#customer-server-1-address:22:/path/to/software/server1:NULL:Customer1name
user2#customer-server-2-address:2222:/path/to/software/server2:/etc/vpnc/client1.conf:Customer2name
user3#customer-server-3-address:22:/path/to/software/server3:NULL:Customer3name
Char ":" acts as field separator; field 1 is the server address, 2 is port, 3 is path to software, 4 is used to tell if a VPN tunnel is to be enabled first, 5 is customer name.
I've managed to create the following script:
#!/bin/bash
[...]
while IFS=':' read -ra array; do
if [ "${array[3]}" != "NULL" ]; then
echo
echo "### USING VPN CONF '${array[3]}' FOR SERVER '${array[0]}'... ###"
sleep 1
#vpnc ${array[3]}
TUNNEL1=$(ifconfig | grep -o eth0)
TUNNEL2='eth0'
if [ "$TUNNEL1" = "$TUNNEL2" ]; then
echo "### TUNNEL IS UP ###"
scp -P${array[1]} $FILENAME.gz ${array[0]}:${array[2]}
scp -P${array[1]} $FILELIST ${array[0]}:${array[2]}
ssh -p${array[1]} ${array[0]} 'cd '${array[2]}' && cat '${array[2]}'/'$FILELIST' | cpio --quiet -H ustar -o -0 -L -F '${array[2]}'/'$BACKUP_FILENAME
ssh -p${array[1]} ${array[0]} 'gzip '${array[2]}'/'$BACKUP_FILENAME
ssh -p${array[1]} ${array[0]} 'tar -C '${array[2]}' -xf '${array[2]}'/'$FILENAME.gz
ssh -p${array[1]} ${array[0]} 'cd '${array[2]}' && mkdir -p '$REMOTE_BACKUP_DIRECTORY' && rm -f '$FILELIST' && mv -f '$BACKUP_FILENAME.gz $REMOTE_BACKUP_DIRECTORY
echo "### SERVER '${array[0]}' UPDATED ###"
#vpnc-disconnect
sleep 1
else
echo "### VPN ERROR IN SERVER '${array[4]}' ###"
fi
else
echo
scp -P${array[1]} $FILENAME.gz ${array[0]}:${array[2]}
scp -P${array[1]} $FILELIST ${array[0]}:${array[2]}
ssh -p${array[1]} ${array[0]} 'cd '${array[2]}' && cat '${array[2]}'/'$FILELIST' | cpio --quiet -H ustar -o -0 -L -F '${array[2]}'/'$BACKUP_FILENAME-${array[4]}
ssh -p${array[1]} ${array[0]} 'gzip '${array[2]}'/'$BACKUP_FILENAME-${array[4]}
ssh -p${array[1]} ${array[0]} 'tar -C '${array[2]}' -xf '${array[2]}'/'$FILENAME.gz
ssh -p${array[1]} ${array[0]} 'cd '${array[2]}' && mkdir -p '$REMOTE_BACKUP_DIRECTORY' && rm -f '$FILELIST' && mv -f '$BACKUP_FILENAME-${array[4]}.gz $REMOTE_BACKUP_DIRECTORY
echo "### SERVER '${array[4]}' UPDATED ###"
echo
fi;
done < "$CUSTOMER_SERVERS_FILE"
$CUSTOMER_SERVERS_FILE is the container file as described earlier, $FILENAME.gz is the update package,
$FILELIST is the list of the files to update. Other variables set for other purposes.
Problem is, this whole thing is effectively running only for the first customer in my $CUSTOMER_SERVERS_FILE. The lines above the first are being skipped, and I can't tell why. Any hints? Thank you.
EDIT: As an answer to the duplicate objection, being the script rather large I didn't think of any link between the while and ssh objects. I was rather thinking more of a syntax error. However, I can still delete the question if asked to do so.
This happens because your while read loop and ssh both read from stdin.
You can fix it by using /dev/null as ssh's stdin:
ssh host cmd < /dev/null

Resources