source: tags/confman-1.5.1/confman @ 123

Revision 123, 13.3 KB checked in by ccowart, 5 years ago (diff)

Developed the pull mechanism for confman. It's ready to go into production!

  • Property rc:mode set to 0555
  • Property svn:executable set to *
  • Property svn:keywords set to Id
Line 
1#! /bin/bash
2#
3# confman provides a command-line interface to Rescomp's server configuration
4# management system.
5#
6# confman help
7#       Print help and usage information
8#
9# Author: Chris Cowart <ccowart@rescomp.berkeley.edu>
10# Date: 30 March 2006
11#
12# $Id$
13
14#. /usr/local/rescomp/lib/confmancommon.sh
15. $HOME/src/sysadmin/confman/confmancommon.sh
16
17# Set a default editor
18if [ -z ${EDITOR} ] ; then
19        if which vim >/dev/null 2>&1 ; then
20                EDITOR="vim"
21        else
22                EDITOR="vi"
23        fi
24fi
25
26# Let's make sure that only you can read your working copy
27# Have to make this less restrictive due to NFS home dirs.
28umask 022
29
30# This function implements the setup subcommand. It is intended to be called
31# with no arguments, and will error if that's not the case.
32function setup {
33        local response
34        $DEBUG && echo "Running setup" >&4
35        if [ ! -z $* ] ; then
36                print_usage 1
37        elif [ -d ${WORK_PATH} ] ; then
38                echo "Looks like ${WORK_PATH} already exists."
39                echo "Start over by removing it? (y/N)"
40                read response
41                if [[ $response =~ '^[yY]([es]|[ES])?' ]] ; then
42                        rm -rf ${WORK_PATH}
43                        setup
44                else
45                        echo "Setup failed." >&4
46                        exit 1
47                fi
48        else
49                conf_checkout_tree
50        fi
51}
52
53function create {
54        local module=$1
55        shift
56        if [ -z $* ] ; then
57                conf_create_module $module
58        else
59                print_usage 1
60        fi
61}
62
63function update {
64        if [ -z $* ] ; then
65                conf_update_tree || conf_cleanexit
66        else
67                print_usage 1
68        fi
69}
70
71function revert {
72        if [ -z $* ] ; then
73                print_usage 1
74        else
75                conf_revert $*
76        fi
77}
78
79function commit {
80        if [ -z $* ] ; then
81                local msg=`mktemp -t confman`
82                # Moved up per Ian's request.
83                echo "Change this file to your log message." > $msg
84                echo "BugId: " >> $msg
85                ${EDITOR} $msg
86                sudo -v
87                update || conf_cleanexit
88
89                echo "Commit operation started" >&2
90        conf_commit "$LAYERS" $msg || return $?
91                for layer in $LAYERS ; do
92                        echo "Rolling on $layer..."
93                        conf_rollout $layer || return $?
94                done
95                for file in $SINGULARITIES ; do
96                        conf_assemble_sing $file || return $?
97                done
98        conf_recordAction commit
99        conf_markclean
100                echo "Commit operation finished successfully" >&2
101                rm -f $msg
102        else
103                print_usage 1
104        fi
105}
106
107# Short name intentional, don't want collision with real install.
108function inst {
109        local file livefile
110
111        if [ -z "$*" ] ; then
112                print_usage 1
113        else
114                local msg=`mktemp -t confman`
115                # Moved up per Ian's request.
116                echo "Change this file to your log message." > $msg
117                echo "BugId: " >> $msg
118                ${EDITOR} $msg
119                sudo -v
120                update || conf_cleanexit
121
122                echo "Installation operation started." >&2
123        conf_commit "$LAYERS" $msg || return $?
124                for layer in $LAYERS ; do
125                        conf_install $layer "$@"
126                done
127                for file in $SINGULARITIES ; do
128                        conf_assemble_sing $file || conf_cleanexit
129                done
130        conf_recordAction install
131        if ! conf_isclean ; then
132            echo "WARNING: Recent 'install' operations prevented a 'sync'" >&2
133            echo "Running a 'commit' is highly recommended." >&2
134        fi
135                echo "Installation operation succeeded." >&2
136        fi
137}
138       
139
140function import {
141       
142        # Check for a force
143        local item OPTIND
144        force=0
145        while getopts "f" opt ; do
146                case $opt in
147                        f)
148                        force=1
149                        shift
150                        ;;
151                        *)
152                        print_help 1
153                        ;;
154                esac
155        done
156
157        local module=$1
158        local response usefile suffix file layer
159        local mode=$DEFAULT_MODE_FILE
160        local owner=$DEFAULT_OWNER
161        local group=$DEFAULT_GROUP
162        local comment=$DEFAULT_COMMENT
163        shift
164        if [ -z $1 ] ; then
165                print_usage 1
166        fi
167
168        sudo -v
169        if [ -r $1 ] ; then
170                file=`abspath $1`
171        else
172                # If we can't enter the parent directory, this will help us
173                # get the info we need.
174                file=`sudo abspath $1`
175        fi
176        shift
177
178
179        # See if we're importing a singularity
180        if [[ "$SINGULARITIES" =~ "$file" ]] ; then
181                suffix="-$module"
182        fi
183
184        # Error out when trying to import a symbolic link.
185        if sudo [ -L $file ] ; then
186                echo "$file is a symbolic link!" >&4
187                conf_cleanexit
188        fi
189
190        if [ -f ${WORK_PATH}/${module}${file}${suffix} ] ; then
191                echo "$file already exists in your working copy of $module." \
192                        "Skipping." >&4
193                import $module $*
194                return
195        fi
196
197        if [ $force = 0 ] ; then
198                for layer in $LAYERS ; do
199                        if [ -f ${WORK_PATH}/${layer}${file}${suffix} ] ; then
200                                echo "$file already exists in the ${layer}" \
201                                     "module. Skipping." >&4
202                                echo "Did you mean -f ?" >&4
203                                import $module $*
204                                return
205                        fi
206                done
207        fi
208
209        if sudo [ -f $file ] ; then
210                eval `sudo stat -f "mode=%Mp%Lp owner=%Su group=%Sg" $file`
211                # Let's make our best guess on the comment character:
212                local tmpfile=`mktemp -t confman`
213                local biggestcount=0
214                local count
215
216                # Let's see if we can read the file as ourself:
217                usefile=`mktemp -t confman`
218                if [ ! -r $file ] ; then
219                        sudo cat $file > $usefile
220                else
221                        cat $file > $usefile
222                fi
223
224                # Put all non-alphanumerics into a file
225                awk '{print $1}' $usefile | egrep -o \
226                        "^[^-_A-Za-z0-9]" > $tmpfile
227
228                for char in `cat $tmpfile | sort | uniq` ; do
229                        count=`egrep -o "\\$char" $tmpfile | wc -l`
230                        if [ $count -gt $biggestcount ] ; then
231                                biggestcount=$count
232                                comment="$char"
233                        fi
234                done
235                rm $tmpfile
236
237                # Convert mode string to base 10:
238                mode=`echo "obase=10;ibase=8;$mode" | bc`
239                # And use a bitmask to subtract off all write-access
240                # 3949d = 7555o
241                mode=$(($mode & 3949))
242                # And back to an octet:
243                mode=`printf '%04o\n' $mode`
244        elif sudo [ -d "$file" ] ; then
245                import $module $* ${file}/*
246                return
247        else
248                # Prompt for file owner
249                echo "Who should be the file's owner? [ $owner ]"
250                read response
251                if [ ! -z $response ] ; then
252                        owner=$response
253                fi
254
255                # And file's group
256                echo "Who should be the file's group? [ $group ]"
257                read response
258                if [ ! -z $response ] ; then
259                        group=$response
260                fi
261
262                # now, the permissions
263                echo "What should the file's permissions be? [ $mode ]"
264                read response
265                if [ ! -z $response ] ; then
266                        mode=$response
267                fi
268
269                # now, the comment character
270                echo "What string starts comment lines? [ $comment ]"
271                read response
272                if [ ! -z $response ] ; then
273                        comment=$response
274                fi
275        fi
276
277        if [ ! -d "${WORK_PATH}/${module}`dirname $file`" ] ; then
278                newdir "${WORK_PATH}/${module}`dirname $file`"
279        fi
280
281        # Time to generate the file
282        conf_gen_file $module "${file}${suffix}" $owner $group \
283                $mode "$comment" $usefile
284
285        # Removing temporary files
286        rm -f $usefile
287
288        # Are there more files to import?
289        if [ ! -z $1 ] ; then
290                import $module $*
291        fi
292
293}
294
295function remove {
296        if [ -z $1 ] ; then print_usage 1 ; fi
297        conf_rm_file $*
298}
299
300function newdir {
301        local dir=$1
302        local response module realpath
303        local mode=$DEFAULT_MODE_DIRECTORY
304        local owner=$DEFAULT_OWNER
305        local group=$DEFAULT_GROUP
306        local comment="dir"
307        local workdir=`abspath .`
308        if [ -z $1 ] ; then
309                print_usage 1
310        fi
311
312        # Find the "real" directory's path
313        if [[ ! $dir =~ "^\/" ]] ; then
314                dir="${workdir}/${dir}"
315        fi
316        module=`echo ${dir#$WORK_PATH} | sed -E 's:/([^/]+)/.*:\1:'`
317        realpath=${dir#${WORK_PATH}/${module}}
318
319        if [ -d $realpath ] ; then
320                eval `sudo stat -f "mode=%Mp%Lp owner=%Su group=%Sg" $realpath`
321
322                # Convert mode string to base 10:
323                mode=`echo "obase=10;ibase=8;$mode" | bc`
324                # And use a bitmask to subtract off all write-access
325                # 3949d = 7555o
326                mode=$(($mode & 3949))
327                # And back to an octet:
328                mode=`printf '%04o\n' $mode`
329        else
330                # Prompt for file owner
331                echo "Who should be the directory's owner? [ $owner ]"
332                read response
333                if [ ! -z $response ] ; then
334                        owner=$response
335                fi
336
337                # And file's group
338                echo "Who should be the directory's group? [ $group ]"
339                read response
340                if [ ! -z $response ] ; then
341                        group=$response
342                fi
343
344                # now, the permissions
345                echo "What should the directory's permissions be? [ $mode ]"
346                read response
347                if [ ! -z $response ] ; then
348                        mode=$response
349                fi
350        fi
351
352        # Time to create the directory.
353        echo "Making directory $dir with ${owner}:${group}, $mode"
354        conf_mkdir $dir $owner $group $mode
355}
356
357function list {
358        local file item
359        if [ -z $1 ] ; then
360                file=`abspath .`
361        else
362                file=`abspath $1`
363        fi
364        echo -e "--------------------------------------------------------"
365        echo -e "Mode\tOwner\tGroup\tComment\t\tFilename"
366        echo -e "--------------------------------------------------------"
367        if [ -f "$file" ] ; then
368                conf_list $file
369        elif [ -d "$file" ] ; then
370                for item in `ls $file` ; do
371                        conf_list "$file/$item"
372                done
373        fi
374}
375
376function status {
377        conf_status $*
378}
379
380function chowner {
381        local recursive item OPTIND
382        while getopts "R" opt ; do
383                case $opt in
384                        R)
385                        recursive=1
386                        shift
387                        ;;
388                        *)
389                        print_help 1
390                        ;;
391                esac
392        done
393        local owner=$1
394        local file=$2
395        conf_set_prop $file owner $owner
396        if [ ! -z $recursive ] && [ -d $file ] ; then
397                for item in $file/* ; do
398                        chowner -R $owner $item
399                done
400        fi
401}
402
403function chgroup {
404        local recursive item OPTIND
405        while getopts "R" opt ; do
406                case $opt in
407                        R)
408                        recursive=1
409                        shift
410                        ;;
411                        *)
412                        print_help 1
413                        ;;
414                esac
415        done
416        local group=$1
417        local file=$2
418        conf_set_prop $file group $group
419        if [ ! -z $recursive ] && [ -d $file ] ; then
420                for item in $file/* ; do
421                        chgroup -R $group $item
422                done
423        fi
424}
425
426function chmode {
427        local recursive item OPTIND
428        while getopts "R" opt ; do
429                case $opt in
430                        R)
431                        recursive=1
432                        shift
433                        ;;
434                        *)
435                        print_help 1
436                        ;;
437                esac
438        done
439        local mode=$1
440        local file=$2
441        conf_set_prop $file mode $mode
442        if [ ! -z $recursive ] && [ -d $file ] ; then
443                for item in $file/* ; do
444                        chmode -R $mode $item
445                done
446        fi
447}
448
449function chcom {
450        local comment="$1"
451        local file=$2
452        conf_set_prop $file comment "$comment"
453}
454
455function checklook {
456        local module=$1
457        local chkdir=${WORK_PATH}/${REPO_CHECKPTS}/${module}
458        if [ -z $1 ] ; then
459                print_usage 1
460        elif [ -d $chkdir ] ; then
461                ls $chkdir
462        else
463                echo "There are no checkpoints for ${module}."
464        fi
465}
466
467function checknew {
468        local module=$1
469        local checkpoint=$2
470        if [ -z $2 ] ; then
471                print_usage 1
472        else
473                conf_new_checkpoint $module $checkpoint
474        fi
475}
476
477function checkclear {
478        local module=$1
479        local checkpoint=$2
480        if [ -z $2 ] ; then
481                print_usage 1
482        else
483                conf_rm_checkpoint $module $checkpoint
484        fi
485}
486
487function rollback {
488        local module=$1
489        local checkpoint=$2
490        local clock=$3
491        if [ -z $2 ] ; then
492                print_usage 1
493        else
494                echo "Rolling $module back to $checkpoint $clock" >&2
495                conf_rollback $module $checkpoint $clock || conf_cleanexit
496                for layer in $LAYERS ; do
497                        echo "Rolling on $layer..."
498                        conf_rollout $layer || conf_cleanexit
499                done
500
501                for file in $SINGULARITIES ; do
502                        conf_assemble_sing $file || conf_cleanexit
503                done
504                echo "Rollback succeeded." >&2
505        fi
506}
507
508function rmmod {
509        local module=$1
510        if [ -z $module ] ; then
511                print_usage 1
512        fi
513        conf_rmmod $module
514}
515
516function rename {
517        local oldmod=$1
518        local newmod=$2
519        if [ -z $newmod ] ; then
520                print_usage 1
521        fi
522        if [ ! -d "${WORK_PATH}/${oldmod}" ] ; then
523                echo "${MYNAME}: Error: ${WORK_PATH}/${oldmod} doesn't exist" >&4
524                conf_cleanexit
525        fi
526        if [ -e "${WORK_PATH}/${newmod}" ] ; then
527                echo "${MYNAME}: Error: ${WORK_PATH}/${newmod}: file exists" >&4
528                conf_cleanexit
529        fi
530        conf_rename $oldmod $newmod
531}
532
533function diff {
534        conf_diff $*
535}
536
537function log {
538        conf_log $*
539}
540
541function copy {
542        local src=$1
543        local dest=$2
544
545        if [ -z $2 ] ; then print_usage 1 ; fi
546
547        conf_cp $src $dest
548}
549
550function move {
551        local src=$1
552        local dest=$2
553
554        if [ -z $2 ] ; then print_usage 1 ; fi
555
556        conf_mv $src $dest
557}
558
559function lsattr {
560    if [ -z "$1" ] ; then
561        conf_lsattr *
562    else
563        conf_lsattr "$@"
564    fi
565}
566
567function chattr {
568    local attr="$1"
569    shift
570    local value="${1:-true}"
571    shift
572    if [ -z "$1" ] ; then print_usage 1 ; fi
573
574    conf_chattr "$attr" "$value" "$@"
575}
576
577function rmattr {
578    local attr="$1"
579    shift
580    if [ -z "$1" ] ; then print_usage 1 ; fi
581
582    conf_rmattr "$attr" "$@"
583}
584
585function state {
586    if conf_isclean ; then
587        echo "This host is clean."
588    else
589        echo "This host may be dirty. Consider running a 'commit' operation"
590    fi
591}
592
593# Dubug mode?
594while getopts "d" opt ; do
595        case $opt in
596                d)
597                DEBUG="true"
598                shift
599                ;;
600                *)
601                print_help 1
602                ;;
603        esac
604done
605
606
607# Dispatch the subcommand. This must happen last and in the global context.
608subcommand=$1
609shift
610case $subcommand in
611    help )                          print_help "$@" ; exit 0 ;;
612    setup|se* )                     setup "$@" ;;
613    status )                        status "$@" ;;
614    state )                         state ;;
615    create|cr* )                    create "$@" ;;
616    update|u* )                     update "$@" ;;
617    commit|com* )                   commit "$@" ;;
618    import|im* )                    import "$@" ;;
619    install|in* )                   inst "$@" ;;
620    remove|rem*|rm )                remove "$@" ;;
621    rev* )                          revert "$@" ;;
622    ren* )                          rename "$@" ;;
623    rmmod )                         rmmod "$@" ;;
624    mkdir|mkd* )                    newdir "$@" ;;
625    list|ls )                       list "$@" ;;
626    lsattr )                        lsattr "$@" ;;
627    chattr )                        chattr "$@" ;;
628    rmattr )                        rmattr "$@" ;;
629    move|mv )                       move "$@" ;;
630    copy|cp )                       copy "$@" ;;
631    diff )                          diff "$@" ;;
632    log )                           log "$@" ;;
633    chmod )                         chmode "$@" ;;
634    chown )                         chowner "$@" ;;
635    chcom )                         chcom "$@" ;;
636    chgrp )                         chgroup "$@" ;;
637    checklook|checklist|chls|chlk ) checklook "$@" ;;
638    checknew|chnw )                 checknew "$@" ;;
639    checkclear|chcl|chrm )          checkclear "$@" ;;
640    rollback|ro* )                  rollback "$@" ;;
641    * )                             print_usage 1 ;;
642esac
643
644exit
645
646# vim:ts=4
647
Note: See TracBrowser for help on using the repository browser.