DockerBashOOP/RunningContainer.shc

183 lines
6.8 KiB
Bash

#
# DockerBashOOP - Implementation of BashOOP for Docker.
# Copyright (C) 2021 Ad5001 <mail@ad5001.eu>
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Lesser General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
property RunningContainer.found false
property RunningContainer.count 0
property RunningContainer.lines
property RunningContainer.id
property RunningContainer.image
property RunningContainer.created
property RunningContainer.status
property RunningContainer.ports
property RunningContainer.name
# Constructor to fetch one or many running container.
# Arguments are the various filters to find containers. See: RunningContainer.filter for reference.
# NOTE: Multiple containers can be matched. If so, all properties contain the value for each container per line.
# NOTE: If no container is found, a message will be printed, and the constructor will exit with false.
# Signature: ([string[] filters])
RunningContainer.constructor() {
args=( "$@" )
this.lines = "$($(Docker.Utils.DockerCommand) ps --all | awk -F " {2,}" 'NR>1 { print $1,";",$2,";",$3,";",$4,";",$5,";",$6,($7 != "" ? (";"$7) : "") }')"
# Apply filters
for ((i=0; i < ${#args[@]}; i++)); do
filterName=${args[$i]}
case $filterName in
with_id | with_image | created | with_status | with_port | named)
# The next argument is the value of the filter, so we skip it.
i=$(expr "$i" + 1)
filterValue=${args[$i]}
this._baseFilter $filterName $filterValue
;;
running | exited | stopped)
this._baseFilter $filterName
;;
*)
echo "Unknown filter $filterName." 1>&2;
;;
esac
done
this._updateProperties
# Print error message in STDERR when no containers are found.
if [ "$(this.found)" == false ]; then echo "No container found matching those filters." 1>&2; fi
}
# Finds all containers in "docker ps" with a certain field matching a value and returns their lines.
# Signature: (<int fieldId>, <string operation>, <string fieldValue>)
RunningContainer.findLineByValue() {
fieldId=$1
operation=$2
fieldValue=$3
# YES. I know. You shouldn't do that with AWK, but variables, FOR SOME REASON, are not properly passed to AWK.
this.lines | awk -F " ; " '$'"$fieldId"' '"$operation"' "'"$fieldValue"'" { print $1,";",$2,";",$3,";",$4,";",$5,";",$6,($7 != "" ? (";"$7) : "") }'
}
# Internal function which filters. See: RunningContainer.filter for reference.
# Signature: (<string filterName>, [string filterValue])
RunningContainer._baseFilter() {
filterName=$1
filterValue=$2
#echo -n "Applying filter $filterName (previous count $(this.lines | wc -l))..." 1>&2
case $filterName in
with_id)
this.lines = "$(this.findLineByValue 1 == $filterValue)"
;;
with_image)
this.lines = "$(this.findLineByValue 2 == $filterValue)"
;;
created)
this.lines = "$(this.findLineByValue 4 == $filterValue)"
;;
with_status)
this.lines = "$(this.findLineByValue 5 == $filterValue)"
;;
running)
this.lines = "$(RunningContainer.findLineByValue 5 ~ "Up")"
;;
exited | stopped)
this.lines = "$(this.findLineByValue 5 "~" "Exited")"
;;
with_port)
this.lines = "$(this.findLineByValue 6 ~ $filterValue)"
;;
named)
lines="$(this.findLineByValue 7 "~" $filterValue)"
if [ -z "$lines" ]; then # Sometimes, when no ports are forwarded, the name is in the 6th field.
lines="$(this.findLineByValue 6 "~" $filterValue)"
fi
this.lines = "$lines"
;;
esac
#echo " New count: $(this.lines | wc -l)." 1>&2
}
# Updates property data from fetched lines.
# No argument
RunningContainer._updateProperties() {
if [ ! -z "$(this.lines)" ]; then
this.found = true
this.count = $(this.lines | wc -l)
this.id = "$(this.lines | awk -F " ; " '{ print $1 }')"
this.image = "$(this.lines | awk -F " ; " '{ print $2 }')"
this.created = "$(this.lines | awk -F " ; " '{ print $4 }')"
this.status = "$(this.lines | awk -F " ; " '{ print $5 }')"
this.ports = "$(this.lines | awk -F " ; " '{ if($7 != "") { print $6 } }')" # If field 7 is null, that means field 6 is the name, so there are no ports.
this.name = "$(this.lines | awk -F " ; " '{ print ($7 != "") ? $7 : $6 }')"
else
this.found = false
this.count = 0
fi
}
# Filters all containers assigned to the instance and removes all instances not corresponding to it.
# Filters with a value: with_id, with_image, created, with_status, with_port, named
# Filters without value: running, exited
# Filter types:
# - "named" to find by name
# - "created" to find by creation date,
# - "with_id" to find by container id
# - "with_image" to find by image
# - "with_status" to check status
# - "with_port" to find all having this port forwarded
# - "running" to find all containers running
# - "exited" or "stopped" to find all containers stopped.
# Signature: (<string filterName>, [string filterValue])
RunningContainer.filter() {
filterName=$1
filterValue=$2
this._baseFilter $filterName $filterValue
this._updateProperties
}
# Applies a docker command to all containers
# Signature: (<string command>, [string[] arguments])
RunningContainer.applyToAll() {
cmd=$1
args=${@:2}
for container in $(this.id); do
$(Docker.Utils.DockerCommand) $cmd $args $container
done
}
# Kills all containers assigned to this instance.
# Signature: ([string[] arguments])
RunningContainer.kill() {
$this.applyToAll kill $@
}
# Removes all containers assigned to this instance.
# Signature: ([string[] arguments])
RunningContainer.rm() {
$this.applyToAll rm $@
}
# Removes all containers assigned to this instance.
# Signature: ([string[] arguments])
RunningContainer.remove() {
$this.applyToAll rm $@
}
# Waits for all containers assigned to this instance to stop and echo their exit code.
# Signature: ([string[] arguments])
RunningContainer.wait() {
$this.applyToAll wait $@
}