summaryrefslogtreecommitdiffstats
path: root/repoman/bin/checkrepo
blob: 5b8a0270dac639f1a12c2cc2c4dd2e0d4fad6b10 (plain)
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
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
#!/bin/bash

#/**
#         checkrepo
#@file    checkrepo
#@brief   Maintain repository information in a JSON file.
#@warning This script uses "jq" command.
#@version 1.1.0 - Initial version.
#@author  Ramón M. Gómez - ETSII Univ. Sevilla
#@date    2017-09-27
#*/ ##


# Global constants definition.
PROG=$(basename "$(realpath "$0")")
OPENGNSYS=/opt/opengnsys
IMAGESDIR=$OPENGNSYS/images
INFOFILE=$OPENGNSYS/etc/repoinfo.json


# Auxiliar functions.

# Metafunction to check if JSON result exists.
function jq() {
    local OUTPUT
    OUTPUT=$($JQ "$@") || return $?
    [[ "$OUTPUT" = "null" ]] && return 1
    echo "$OUTPUT"
}

# Create/edit JSON file about installed ogLive clients.
function addToJson() {
    # Parameters and variables.
    local IMAGENAME="$1" IMAGETYPE="$2" DATA="$3" JSON i j n m OUNAME OUIND IMGIND
    local CLONATOR COMPRESSOR FSTYPE DATASIZE CLIENT
    IFS=":" read -r CLONATOR COMPRESSOR FSTYPE DATASIZE CLIENT <<<"$DATA"
    # Check if image is restricted to an OU (subdir).
    if [[ $IMAGENAME =~ / ]]; then
        OUNAME="${IMAGENAME%/*}"
        IMAGENAME="${IMAGENAME##*/}"
    fi
    # Data size must be numeric (in KB).
    [[ $DATASIZE =~ ^[0-9]*$ ]] || DATASIZE=0
    # JSON-formatted new entry.
    JSON=$(cat << EOT | jq .
{
  "name":"$IMAGENAME",
  "type":"${IMAGETYPE,,}",
  "clientname":"$CLIENT",
  "clonator":"${CLONATOR,,}",
  "compressor":"${COMPRESSOR,,}",
  "filesystem":"${FSTYPE^^}",
  "datasize":$[ DATASIZE * 1024]
}
EOT
    )
    # Check JSON file consistency.
    if [ "$(jq -c keys $INFOFILE 2>/dev/null)" == '["directory","images","ous"]' ]; then
        # Common image.
        if [ -z "$OUNAME" ]; then
            # Check if the image is defined into JSON file.
            n=$(jq ".images | length" $INFOFILE)
            for ((i=0; i<n; i++)); do
                [ "$(jq ".check=$JSON | .check.name==.images[$i].name" $INFOFILE)" == "true" ] && IMGIND=$i
            done
            # Check if it needs to update or insert data.
            if [ -n "$IMGIND" ]; then
                # Update if image data changes and info file exists.
                [ -n "$3" -a "$(jq ".check=$JSON | .check==.images[$IMGIND]" $INFOFILE)" == "false" ] && jq ".images[$IMGIND]=$JSON" $INFOFILE | sponge $INFOFILE
            else
                # Append a new entry.
                jq ".images |= (. + [$JSON])" $INFOFILE | sponge $INFOFILE
            fi
        else    # OU image.
            # Append a new OU entry if it does not exist.
            if [ -z "$(jq -r ".ous[].subdir" $INFOFILE | grep "^$OUNAME$")" ]; then
                JSON=$(cat << EOT | jq .
{ 
  "subdir": "$OUNAME",
  "images": [ $JSON ]
}
EOT
                )
                jq ".ous |= (. + [$JSON])" $INFOFILE | sponge $INFOFILE
            else
                # Check if the image is defined in some OU.
                m=$(jq ".ous | length" $INFOFILE)
                for ((j=0; j<m; j++)); do
                    n=$(jq ".ous[$j].images | length" $INFOFILE)
                    for ((i=0; i<n; i++)); do
                        [ "$(jq ".check=$JSON | .check.name==.ous[$j].images[$i].name" $INFOFILE)" == "true" ] && OUIND=$j && IMGIND=$i
                    done
                done
                # Check if it needs to update or insert data.
                if [ -n "$IMGIND" ]; then
                    # Update if image data changes and info file exists.
                    [ $# -gt 2 -a "$(jq ".check=$JSON | .check==.ous[$OUIND].images[$IMGIND]" $INFOFILE)" == "false" ] && jq ".ous[$OUIND].images[$IMGIND]=$JSON" $INFOFILE | sponge $INFOFILE
                else
                    # Append a new entry.
                    jq ".ous[$OUIND].images |= (. + [$JSON])" $INFOFILE | sponge $INFOFILE
                fi
            fi
        fi
    else
        # Create new JSON file.
        if [ -z "$OUNAME" ]; then
            cat << EOT | jq . > $INFOFILE
{"directory":"$IMAGESDIR","images":[${IMAGENAME:+$JSON}],"ous":[]}
EOT
        else
            cat << EOT | jq . > $INFOFILE
{"directory":"$IMAGESDIR","images":[],"ous":[{"subdir":"$OUNAME","images":[$JSON]}]}
EOT
        fi
    fi
}

# Show an error message.
function raiseError() {
    case "$1" in
        usage)
            echo "$PROG: Usage error: Type \"$PROG help\"" >&2
            exit 1 ;;
        notfound)
            echo "$PROG: Resource not found: $2" >&2
            exit 2 ;;
        access)
            echo "$PROG: Access error: $2" >&2
            exit 3 ;;
        *)
            echo "$PROG: Unknown error" >&2
            exit 1 ;;
    esac
}

# Command functions.

# Show help message.
function help() {
    cat << EOT
$PROG: maintain the repository information.
Usage: $PROG
EOT
}

# Check for file-based images to update the repository configuration file.
function checkfiles() {
    local IMAGES IMG INFO DATA

    # File-stored images.
    IMAGES=$(find $IMAGESDIR -maxdepth 2 -type f \( -name "*.img" -o -name "*.dsk" \) -print)
    for IMG in $IMAGES; do
        # Skip locked images.
        [ -e "$IMG.lock" ] && continue
        # Retrieve image creation data and delete temporary file.
        INFO="$IMG.info"
        [ -e "$INFO" -a "$INFO" -ot "$IMG" ] && rm -f "$INFO" && echo "Warning: Deleted outdated file $INFO"
        DATA=""
        [ -r "$INFO" ] && DATA=$(cat "$INFO")
        # Add data to configuration file (name, type and data) and remove image info file.
        IMG=${IMG#$IMAGESDIR/}
        addToJson "${IMG%.*}" "${IMG##*.}" "$DATA" && rm -f "$INFO"
    done
}

# Check for directory-based images to update the repository configuration file.
function checkdirs() {
    local IMAGES IMG INFO DATA

    # Directory-based images.
    IMAGES=$(find $IMAGESDIR -maxdepth 3 -type f -name ogimg.info -print)
    for INFO in $IMAGES; do
        IMG="$(dirname "${INFO#$IMAGESDIR/}")"
        # Skip repository root directory and locked images.
        [ "$IMG" == "$IMAGESDIR" -o -e "$IMG.lock" ] && continue
        DATA=$(awk -F= '$1=="# fstype" {fs=$2} $1=="# sizedata" {sz=$2} END {printf "rsync::%s:%s:",fs,sz}' "$INFO")
        # Add data to configuration file (name, type and data).
        addToJson "$IMG" "dir" "$DATA"
    done
}

# Check if images are removed to update the repository configuration file.
function checkremoved() {
    local IMG TYPE OU i j n m
    [ ! -w "$INFOFILE" ] && raiseError access "$INFOFILE"

    # Check if global images are defined into JSON file.
    n=$(jq ".images | length" $INFOFILE)
    for ((i=0; i<n; i++)); do
        # Image name and type.
        IMG="$(jq -r ".images[$i].name" $INFOFILE)"
        TYPE="$(jq -r ".images[$i].type" $INFOFILE)"
        [ "$TYPE" != "dir" ] && IMG="$IMG.$TYPE"
        # Delete entry if image does not exist and it's not locked.
        [ ! -e "$IMAGESDIR/$IMG" -a ! -e "$IMAGESDIR/$IMG.lock" ] && jq "del(.images[$i])" $INFOFILE | sponge $INFOFILE
    done
    # Check if OU images are defined into JSON file.
    m=$(jq ".ous | length" $INFOFILE)
    for ((j=0; j<m; j++)); do
        # OU subdir.
        OU="$(jq -r ".ous[$j].subdir" $INFOFILE)"
        # Delete OU's entries if its subdir does not exist.
        if [ ! -e "$IMAGESDIR/$OU" ]; then
            jq "del(.ous[$j])" $INFOFILE | sponge $INFOFILE
        else
            n=$(jq ".images | length" $INFOFILE)
            for ((i=0; i<n; i++)); do
                # Image name and type.
                IMG="$(jq -r ".ous[$j].images[$i].name" $INFOFILE)"
                TYPE="$(jq -r ".ous[$j].images[$i].type" $INFOFILE)"
                [ "$TYPE" != "dir" ] && IMG="$IMG.$TYPE"
                # Delete entry if image does not exist and it's not locked.
                [ ! -e "$IMAGESDIR/$OU/$IMG" -a ! -e "$IMAGESDIR/$OU/$IMG.lock" ] && jq "del(.ous[$j].images[$i])" $INFOFILE | sponge $INFOFILE
            done
        fi
    done
}


# Main progrram.

# Check dependencies.
JQ=$(which jq 2>/dev/null) || raiseError notfound "Need to install \"jq\"."
which sponge &>/dev/null || raiseError notfound "Need to install \"moreutils\"."
[ ! -w "$(dirname "$INFOFILE")" ] && raiseError access "$INFOFILE"
[ -e "$INFOFILE" ] || addToJson

checkfiles
checkdirs
checkremoved