1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
|
#!/bin/bash
#/**
#@file importimage
#@usage importimage [str_user] str_repo str_imagename
#@brief Imports an image file from other repository
#@param str_user username to access the remote repository (local user, by default)
#@param str_repo repository IP address or hostaname
#@param str_imagename image name to download
#@warning Program will request the repository REST token.
#@version 1.1.1 - Initial version
#@author Ramón M. Gómez, ETSII Universidad de Sevilla
#@date 2018-10-08
#*/
# Variables.
PROG="$(basename "$0")"
OPENGNSYS="/opt/opengnsys"
REPODIR="$OPENGNSYS/images"
REPOCONF="$OPENGNSYS/etc/ogAdmRepo.cfg"
SERVERCONF="$OPENGNSYS/etc/ogAdmServer.cfg"
DEFAULTFILE="/etc/default/opengnsys"
MYCNF=$(mktemp /tmp/.my.cnf.XXXXX)
let BACKUP=0
source $DEFAULTFILE
source $REPOCONF &>/dev/null
[ "$RUN_OGADMSERVER" == "yes" ] && source $SERVERCONF &>/dev/null
# Functions.
source $OPENGNSYS/lib/ogfunctions.sh
# Main program.
# Error control.
[ "$USER" == "root" ] || raiseError access "Need to be root."
[ "$RUN_OGADMREPO" == "yes" ] || raiseError access "This server is not defined as image repository."
[ -w "$REPODIR" ] || raiseError access "Cannot write in local repository."
[ -n "$IPlocal" ] || raiseError access "Cannot read repository configuration file."
case $# in
2) USERNAME="$SUDO_USER"; REPO="$1"; IMAGE="$2" ;;
3) USERNAME="$1"; REPO="$2"; IMAGE="$3" ;;
*) [ "$*" == "help" ] && help || raiseError usage
esac
[ "${REPO,,}" == "${HOSTNAME,,}" ] || [ "${REPO,,}" == "localhost" ] || [[ ${REPO} =~ ^127\. ]] || [ "${REPO,,}" == "${IPlocal,,}" ] && raiseError access "Cannot import from local repository."
# Fetching image info from the repository.
read -rp "Enter repository API token: " APITOKEN
IMAGEINFO="$(curl -k -H "Authorization: $APITOKEN" "https://$REPO/opengnsys/rest/repository/image/$IMAGE" 2> /dev/null | jq -r .)"
IMAGENAME="$(jq -r '.name' <<< "$IMAGEINFO" 2>/dev/null)"
case "$IMAGEINFO" in
"") # Connection error.
raiseError access "Cannot connect to $REPO" ;;
"[]") # Image not found.
raiseError notfound "Image $IMAGE in remote repository $REPO" ;;
*) # Checking REST error.
MESSAGE="$(jq -r '.message' <<< "$IMAGEINFO" 2>/dev/null)"
[ -n "$MESSAGE" ] && raiseError access "$MESSAGE"
esac
IMAGETYPE="$(jq -r '.type' <<< "$IMAGEINFO" 2>/dev/null)"
IMAGELOCKED="$(jq -r '.locked' <<< "$IMAGEINFO" 2>/dev/null)"
[ "$IMAGELOCKED" == "true" ] && raiseError access "Image locked by remote repository."
IMAGESIZE="$(jq -r '.size' <<< "$IMAGEINFO" 2>/dev/null)"
[ -z "$IMAGESIZE" ] && raiseError access "Cannot retrieve image size"
# Checking if local image exists.
IMAGEPATH="$REPODIR/$IMAGENAME.$IMAGETYPE"
if [ -e "$IMAGEPATH" ]; then
# Checking if local image is locked.
LOCKFILE="$IMAGEPATH.lock"
[ -f "$LOCKFILE" ] && raiseError access "Local image is locked, cannot write."
# Confirm image download.
read -rp "Image $IMAGENAME exists in the local repository. Do you want to continue? (y/N): " ANSWER
[ "${ANSWER,,}" = "y" ] || exit
BACKUP=1
REMOTEDATE=$(jq -r '.modified' <<< "$IMAGEINFO" 2>/dev/null)
LOCALDATE=$(stat -c "%y" "$IMAGEPATH" | cut -f1 -d.)
if [[ "$REMOTEDATE" < "$LOCALDATE" ]]; then
read -rp "Remote image seems older than the local one. Do you want to continue? (y/N): " ANSWER
[ "${ANSWER,,}" = "y" ] || exit
fi
fi
# Trapping signal to unlock image before exit.
trap "rm -f $LOCKFILE $MYCNF" 1 2 3 6 9 15
# Creating lock file.
touch $LOCKFILE
# Backing up local image.
if [ $BACKUP -eq 1 ]; then
mv -vf "$IMAGEPATH" "$IMAGEPATH.ant" 2>/dev/null
mv -vf "$IMAGEPATH.torrent" "$IMAGEPATH.torrent.ant" 2>/dev/null
mv -vf "$IMAGEPATH.sum" "$IMAGEPATH.sum.ant" 2>/dev/null
mv -vf "$IMAGEPATH.full.sum" "$IMAGEPATH.full.sum.ant" 2>/dev/null
fi
# Downloading image file.
[[ $IMAGEPATH =~ / ]] && mkdir -p "$(dirname "$IMAGEPATH")"
scp "$USERNAME@$REPO:$IMAGEPATH" $REPODIR
ERRCODE=$?
if [ $ERRCODE -eq 0 ]; then
# Cheking image size.
DOWNLOADSIZE=$(stat -c "%s" "$IMAGEPATH")
[ $IMAGESIZE -ne $DOWNLOADSIZE ] && echo "Warning: image sizes differ: source=$IMAGESIZE, target=$DOWNLOADSIZE."
# Storing creation info.
jq -r '.clonator+":"+.compressor+":"+.filesystem+":"+(.datasize|tostring)+":"' <<<"$IMAGEINFO" > "$IMAGEPATH.info"
# Updating the database when the repo is also configured as Administration Server.
if [ "$RUN_OGADMSERVER" == "yes" ]; then
# Creating credentials file.
cat << EOT > $MYCNF
[client]
user=$USUARIO
password=$PASSWORD
EOT
if [ $BACKUP -eq 1 ]; then
# If the image exists, increase its revision number.
mysql --defaults-extra-file=$MYCNF -D "$CATALOG" -e \
"UPDATE imagenes
SET revision = revision + 1
WHERE nombreca='$IMAGE';" || \
echo "Warning: database cannot be updated."
else
# Obtaining defined Organizational Units.
while read -re DATA; do
OUS[${#OUS[@]}]="$DATA"
done <<<$(mysql --defaults-extra-file=$MYCNF -D "$CATALOG" -Nse \
"SELECT idcentro, nombrecentro FROM centros;")
if [ ${#OUS[@]} -eq 1 ]; then
# Only 1 OU is defined.
let OUID="${OUS%% *}"
else
# Choose image OU.
echo "Choose Organization Unit:"
PS3="Enter number: "
select opt in "${OUS[@]#* }"; do
[ -n "$opt" ] && let OUID="${OUS[REPLY-1]%% *}" && break
done
fi
# Creating a new image associated with an empty software profile.
mysql --defaults-extra-file=$MYCNF -D "$CATALOG" -e \
"SET @repoid = (SELECT idrepositorio FROM repositorios
WHERE ip='$IPlocal' LIMIT 1),
@profname = '$IMAGE imported from $REPO';
INSERT INTO perfilessoft (descripcion, idcentro, grupoid)
SELECT @profname, '$OUID', 0 FROM DUAL
WHERE NOT EXISTS
(SELECT descripcion FROM perfilessoft
WHERE descripcion=@profname AND idcentro='$OUID')
LIMIT 1;
SET @profid = LAST_INSERT_ID();
INSERT INTO imagenes
(nombreca, revision, idperfilsoft, idcentro, comentarios, grupoid, idrepositorio, fechacreacion)
VALUES ('$IMAGE', 1, @profid, '$OUID', 'Image imported from repo $REPO', 0, @repoid, NOW());" || \
echo "Warning: database cannot be updated."
fi
fi
else
# On download error, trying to recover backup.
raiseError download "$USERNAME@$REPO:$IMAGEPATH"
if [ $BACKUP -eq 1 ]; then
mv -vf "$IMAGEPATH.ant" "$IMAGEPATH" 2>/dev/null
mv -vf "$IMAGEPATH.torrent.ant" "$IMAGEPATH.torrent" 2>/dev/null
mv -vf "$IMAGEPATH.sum.ant" "$IMAGEPATH.sum" 2>/dev/null
mv -vf "$IMAGEPATH.full.sum.ant" "$IMAGEPATH.full.sum" 2>/dev/null
fi
fi
# Unlocking image and removing temporary file.
rm -f $LOCKFILE $MYCNF
|