New functions.ksh
1 #
2 # CDDL HEADER START
3 #
4 # The contents of this file are subject to the terms of the
5 # Common Development and Distribution License (the License).
6 # You may not use this file except in compliance with the License.
7 #
8 # You can obtain a copy of the license at usr/src/CDDL.txt
9 # or http://www.opensolaris.org/os/licensing.
10 # See the License for the specific language governing permissions
11 # and limitations under the License.
12 #
13 # When distributing Covered Code, include this CDDL HEADER in each
14 # file and include the License file at usr/src/CDDL.txt.
15 # If applicable, add the following below this CDDL HEADER, with the
16 # fields enclosed by brackets [] replaced with your own identifying
17 # information: Portions Copyright [yyyy] [name of copyright owner]
18 #
19 # CDDL HEADER END
20 #
21
22 #
23 # Copyright 2008 Sun Microsystems, Inc. All rights reserved.
24 # Use is subject to license terms.
25 #
26
27 # ident "%Z%%M% %I% %E% SMI"
28
29 PKG=SUNWscPostgreSQL
30 METHOD=`basename $0`
31 TASK_COMMAND=""
32
33 ZONENAME=/usr/bin/zonename
34 DIRNAME=/usr/bin/dirname
35
36 SCLOGGER=/usr/cluster/lib/sc/scds_syslog
37 PMFADM=/usr/cluster/bin/pmfadm
38 GETENT=/usr/bin/getent
39 AWK=/usr/bin/awk
40 NAWK=/usr/bin/nawk
41 CAT=/usr/bin/cat
42 EGREP=/usr/bin/egrep
43 GREP=/usr/bin/grep
44 ENV=/usr/bin/env
45 HEAD=/usr/bin/head
46 PS=/usr/bin/ps
47 PGREP=/usr/bin/pgrep
48 KILL=/usr/bin/kill
49 IPCS=/usr/bin/ipcs
50 IPCRM=/usr/bin/ipcrm
51 ECHO=/usr/bin/echo
52 TR=/usr/bin/tr
53 SU=/usr/bin/su
54 RM=/usr/bin/rm
55 ZLOGIN=/usr/sbin/zlogin
56 TEST=/usr/bin/test
57 PING=/usr/sbin/ping
58 SED=/usr/bin/sed
59 IFCONFIG=/usr/sbin/ifconfig
60 SSH=/usr/bin/ssh
61 SSH_AGENT=/usr/bin/ssh-agent
62 PKILL=/usr/bin/pkill
63 WC=/usr/bin/wc
64 SLEEP=/usr/bin/sleep
65 TOUCH=/usr/bin/touch
66 CHOWN=/usr/bin/chown
67 CP=/usr/bin/cp
68
69 get_fmri_parameters ()
70 {
71
72 # extract the smf properties, you need to call your agent commands
73
74 debug_message "Function: get_fmri_parameters - Begin "
75 ${SET_DEBUG}
76
77 # Resource name
78
79 RESOURCE=`/usr/bin/svcprop -p parameters/Resource ${SMF_FMRI}`
80
81 # Resource Group
82
83 RESOURCEGROUP=`/usr/bin/svcprop -p parameters/Resource_group ${SMF_FMRI}`
84
85 # Start Project
86
87 Project=:default
88 if /usr/bin/svcprop ${SMF_FMRI}|grep start/project >/dev/null
89 then
90 Project=`/usr/bin/svcprop -p start/project ${SMF_FMRI}`
91 if [ "${Project}" != ":default" ]
92 then
93 PROJ_OPT=" -P ${Project}"
94 ZONE_PROJECT=${Project}
95 fi
96 fi
97
98 # Parameter file
99
100 PARFILE=`/usr/bin/svcprop -p parameters/Parameter_File ${SMF_FMRI}`
101
102 debug_message "Function: get_fmri_parameters - End "
103 }
104
105 set_shell_specifics()
106 {
107
108 # Set variables to construct sourcing and output redirection depending
109 # on the login shell of the user
110
111 debug_message "Function: set_shell_specifics - Begin"
112 ${SET_DEBUG}
113
114 ENVSC=
115
116 if /usr/bin/getent passwd ${USER} | /usr/bin/awk -F: '{print $7}' | /usr/bin/grep csh > /dev/null
117 then
118
119 # C shell specifics
120
121 # sourcing
122
123 if [ -n "${ENVSCRIPT}" ]
124 then
125 ENVSC="source ${ENVSCRIPT};"
126 fi
127
128 # brackets for subshells
129
130 OPEN_BRACKET="("
131 CLOSE_BRACKET=")"
132
133 # redirection
134
135 OUTPUT_APP=">>& ${LOGFILE}"
136 OUTPUT=">& ${LOGFILE}"
137 CAT_OUTPUT="> /tmp/${RESOURCE}-${USER}-cat-out"
138 CAT_ERRPUT=">& /tmp/${RESOURCE}-${USER}-cat-err"
139 TBL_OUTPUT="> /tmp/${RESOURCE}-${USER}-tbl-out"
140 TBL_ERRPUT=">& /tmp/${RESOURCE}-${USER}-tbl-err"
141 else
142
143 # Korn shell specifics
144
145 # sourcing
146
147 if [ -n "${ENVSCRIPT}" ]
148 then
149 ENVSC=". ${ENVSCRIPT};"
150 fi
151
152 # no subshell needed in a ksh
153
154 OPEN_BRACKET=
155 CLOSE_BRACKET=
156
157 # redirection
158
159 OUTPUT_APP=">> ${LOGFILE} 2>&1"
160 OUTPUT="> ${LOGFILE} 2>&1"
161 CAT_OUTPUT="> /tmp/${RESOURCE}-${USER}-cat-out"
162 CAT_ERRPUT="2> /tmp/${RESOURCE}-${USER}-cat-err"
163 TBL_OUTPUT="> /tmp/${RESOURCE}-${USER}-tbl-out"
164 TBL_ERRPUT="2> /tmp/${RESOURCE}-${USER}-tbl-err"
165 fi
166
167
168 debug_message "Function: set_shell_specifics - End"
169 }
170
171 create_pfile()
172 {
173
174 # Creation of the parameter file. This function is used at registration
175 # time only.
176
177 debug_message "Function: create_pfile - Begin "
178 ${SET_DEBUG}
179
180 if [ -z "${PFILE}" ]
181 then
182 ${ECHO} "ERROR: set the variable parameter file"
183 return 1
184 fi
185
186 # determine wether the parameter file needs to be created in a zone or not
187
188 zonecmd=
189
190 pfile_tmp="/tmp/pgspfile.${RS}"
191
192 # get the zonename of the resource group
193
194 target_zone=$(rgs_zonename)
195 if [ -n "${target_zone}" ]
196 then
197 zonecmd="${ZLOGIN} ${target_zone}"
198 fi
199
200 # check the directory of the parameter file
201
202 pdir=`${zonecmd} ${DIRNAME} ${PFILE}`
203
204 # test for the existance of the parameter files directory either in the local or
205 # the global zone according to the zone entry in the nodelist
206
207 if ! ${zonecmd} ${TEST} -d ${pdir}
208 then
209 ${ECHO} "ERROR: set the variable parameter file in an existing directory"
210 return 1
211 fi
212
213 # create the parameter file
214
215 ${ECHO} "Prepare the parameter file ${PFILE}"
216
217 ${CAT} <<EOF > ${pfile_tmp}
218
219 #
220 # Content for the parameter file
221 #
222 # USER - The Solaris user, which owns the PostgreSQL database
223 # PGROOT - Contains the path to the PostgreSQL directory. Below this
224 # directory the postgres binaries are located in the ./bin
225 # directory.
226 # PGDATA - Contains the path to the databases of this specific PostgreSQL
227 # instance. The pg_hba.conf needs to be here.
228 # PGPORT - Port where the postmaster process will be listening to.
229 # PGHOST - Hostname where the postmaster process is listening to, or a directory where the
230 # Unix socket file is stored.
231 # If set to a valid hostname, the PGHOST variable forces the probe to
232 # traverse the TCP/IP stack. If the PGHOST variable is empty or starts with a "/",
233 # the probe will use a socket. If the PGHOST variable starts with a "/", the entry must
234 # be the directory which contains the socket file.
235 # PGLOGFILE - Logfile where the log messages of the postmaster will be stored.
236 # LD_LIBRARY_PATH - This path contains all the necessary libraries for this PostgreSQL
237 # installation.
238 # Optional
239 # ENVSCRIPT - Script to contain PostgreSQL specific runtime variables.
240 # Optional
241 # SCDB - This specific PostgreSQL database will be monitored.
242 # SCUSER - PostgresSQL user to connect to the $SCDB database.
243 # SCTABLE - Table name in the $SCDB database. This table name will be manipulated
244 # to check if PostgreSQL is alive. This table will be generated at database
245 # preparation time.
246 # SCPASS - Password of the SCUSER. If no password is provided the authentication method
247 # for the SCDB database needs to be trusted for requests from the localhost.
248 # Optional
249 # NOCONRET - Return code for connection errors. This return code has to follow the rules
250 # for the generic data service. The value has to be between 1 and 100.
251 # 100/NOCONRET defines the number of consecutive probes to ignore for failed
252 # connections. A restart or failover will occur, if the number is exeeded within
253 # the retry interval.
254
255
256 USER=${USER}
257 PGROOT=${PGROOT}
258 PGDATA=${PGDATA}
259 PGPORT=${PGPORT}
260 PGHOST=${PGHOST}
261 PGLOGFILE=${PGLOGFILE}
262 LD_LIBRARY_PATH=${LD_LIBRARY_PATH}
263 ENVSCRIPT=${ENVSCRIPT}
264 SCDB=${SCDB}
265 SCUSER=${SCUSER}
266 SCTABLE=${SCTABLE}
267 SCPASS=${SCPASS}
268 NOCONRET=${NOCONRET}
269
270 # The following parameters need to be configured only if logfile shipping is configured to ship
271 # the PosgreSQL WAL logs between a designated primary and a designated standby resource.
272 # They need to be configured only on the primary.
273
274 # STDBY_RS The resource name of the PostgreSQL standby resource.
275 # STDBY_RG The resource group name of the PostgreSQL standby resource group.
276 # STDBY_USER User which is the owner of the standby postgres database.
277 # STDBY_HOST Resolvable name of the standby host or the standby zone,
278 # this name has to be reachable via ssh.
279 # STDBY_PARFILE The standbys postgres parameter file to get the rest of the necessary parameters.
280 # STDBY_PING The number of of packets the primary uses to ping the standby host. If this variable is
281 # empty, it will be set to 5 packets.
282 # ROLECHG_RS The rolechangers resource name.
283 # SSH_PASSDIR A directory where the ssh passphrase is stored in a the file <resourcename>-phrase.
284 # This parameter is needed only if you configured WAL file shipping and secured your
285 # ssh key with a passphrase.
286 # Leave it undefined if the passprase is empty.
287 #
288 # If you configure the logfile shipping in a shared nothing topology, do not set the LH parameter.
289 #
290 # Configure the following paramters on the primary host.
291
292 STDBY_RS=${STDBY_RS}
293 STDBY_RG=${STDBY_RG}
294 STDBY_USER=${STDBY_USER}
295 STDBY_HOST=${STDBY_HOST}
296 STDBY_PARFILE=${STDBY_PARFILE}
297 STDBY_PING=${STDBY_PING}
298 #
299 # Configure the following paramter on the standby host.
300 #
301 ROLECHG_RS=${ROLECHG_RS}
302 #
303 # Configure the following parameter on both hosts.
304 #
305 SSH_PASSDIR=${SSH_PASSDIR}
306
307 EOF
308 if [ $? -ne 0 ]
309 then
310 ${ECHO} "ERROR: could not create the temporary parameter file ${pfile_tmp}"
311 return 1
312 fi
313
314 # create the parameter file either in the global or in the prepared target zone
315
316 if [ -n "${target_zone}" ]
317 then
318 ${CAT} ${pfile_tmp} | ${zonecmd} ${CAT} - \>${PFILE}
319 if [ $? -ne 0 ]
320 then
321 ${ECHO} "ERROR: could not create the parameter file ${PFILE}"
322 return 1
323 fi
324 else
325 ${CAT} ${pfile_tmp} > ${PFILE}
326 if [ $? -ne 0 ]
327 then
328 ${ECHO} "ERROR: could not create the parameter file ${PFILE}"
329 return 1
330 fi
331 fi
332
333 debug_message "Function: create_pfile - End "
334 return 0
335 }
336
337 validate_options()
338 {
339 debug_message "Function: validate_options - Begin"
340 ${SET_DEBUG}
341
342 #
343 # Ensure all mandatory options are set
344 #
345
346 for i in RESOURCE RESOURCEGROUP PARFILE
347 do
348 case ${i} in
349 RESOURCE)
350 if [ -z "${RESOURCE}" ]; then
351 # SCMSGS
352 # @explanation
353 # The start, stop or probe command requires an
354 # option which is not set.
355 # @user_action
356 # Fix the start, stop or probe command in the
357 # SUNW.gds resource.
358 scds_syslog -p daemon.err -t $(syslog_tag) -m \
359 "Function: validate_options: %s Option %s not set" \
360 "${METHOD}" "-R"
361 return 1
362 fi;;
363
364 RESOURCEGROUP)
365 if [ -z "${RESOURCEGROUP}" ]; then
366 scds_syslog -p daemon.err -t $(syslog_tag) -m \
367 "Function: validate_options: %s Option %s not set" \
368 "${METHOD}" "-G"
369 return 1
370 fi;;
371
372 PARFILE)
373 if [ -z "${PARFILE}" ]; then
374 scds_syslog -p daemon.err -t $(syslog_tag) -m \
375 "Function: validate_options: %s Option %s not set" \
376 "${METHOD}" "-P"
377 return 1
378 fi;;
379 esac
380 done
381
382 debug_message "Function: validate_options - End"
383 }
384
385 validate()
386 {
387 #
388 # Validate
389 #
390
391 debug_message "Function: validate - Begin"
392 ${SET_DEBUG}
393
394 rc_validate=0
395
396 if ! val_parfile ${PARFILE} "USER PGROOT PGDATA PGPORT PGLOGFILE SCDB SCUSER SCTABLE NOCONRET"
397 then
398 debug_message "Function: validate - End"
399 rc_validate=1
400 return ${rc_validate}
401 fi
402
403 . ${PARFILE}
404
405 for i in `${CAT} ${PARFILE} |grep -v "^#"|grep -v "^ "|nawk -F= '{print $1}'`
406 do
407 case $i in
408 USER)
409
410 # Test the PostgresSQL OS user
411
412 if [ -z "${USER}" ]; then
413 # SCMSGS
414 # @explanation
415 # A mandatory variable is unset in the
416 # parameter file.
417 # @user_action
418 # Fix the parameter file and provide a value
419 # for the variable in the parameter file
420 scds_syslog -p daemon.err -t $(syslog_tag) -m \
421 "Function: validate: The %s variable is not set, but it is required" \
422 "USER"
423 rc_validate=1
424 else
425 id ${USER} >/dev/null 2>&1
426 if [ $? -ne 0 ]; then
427 # SCMSGS
428 # @explanation
429 # The user mentioned in the parameter
430 # file is not defined in the OS.
431 # @user_action
432 # Fix the parameter file and provide
433 # an existing user for the variable
434 # USER.
435 scds_syslog -p daemon.err -t $(syslog_tag) -m \
436 "Function: validate: User %s does not exist, an existing user is required" \
437 "${USER}"
438 rc_validate=1
439 else
440 debug_message "Function: validate - USER OK"
441 fi
442 fi;;
443
444 PGROOT)
445
446 # Test the PG Root variable
447
448 if [ -z "${PGROOT}" ]; then
449 scds_syslog -p daemon.err -t $(syslog_tag) -m \
450 "Function: validate: The %s variable is not set, but it is required" \
451 "PGROOT"
452 rc_validate=1
453 else
454 if [ ! -d ${PGROOT} ]; then
455 # SCMSGS
456 # @explanation
457 # The directory mentioned in the
458 # parameter file for the PGROOT or
459 # PGDATA variable does not exist.
460 # @user_action
461 # Fix the parameter file and provide
462 # an existing directoy for the
463 # variable PGROOT or PGDATA.
464 scds_syslog -p daemon.err -t $(syslog_tag) -m \
465 "Function: validate: Directory %s does not exist, an existing directory is required" \
466 "${PGROOT}"
467 rc_validate=1
468 fi
469
470 # test if it is a postgres installation
471
472 if [ ! -f ${PGROOT}/bin/pg_ctl ]
473 then
474 # SCMSGS
475 # @explanation
476 # The directory mentioned in the
477 # PGROOT variable does not contain the
478 # PostgreSQL binaries in its bin
479 # directory.
480 # @user_action
481 # Provide the directory which does
482 # contain at least the PostgreSQL
483 # binaries in the path ./bin.
484 scds_syslog -p daemon.err -t $(syslog_tag) -m \
485 "Function: validate: Directory %s does not contain the PostgreSQL binaries" \
486 "${PGROOT}"
487 rc_validate=1
488 else
489 debug_message "Function: validate - PGROOT OK"
490 fi
491 fi;;
492
493 PGDATA)
494
495 # Test the PG Data variable
496
497 if [ -z "${PGDATA}" ]; then
498 scds_syslog -p daemon.err -t $(syslog_tag) -m \
499 "Function: validate: The %s variable is not set, but it is required" \
500 "PGDATA"
501 rc_validate=1
502 else
503 if [ ! -d ${PGDATA} ]; then
504 scds_syslog -p daemon.err -t $(syslog_tag) -m \
505 "Function: validate: Directory %s does not exist, an existing directory is required" \
506 "${PGDATA}"
507 rc_validate=1
508 fi
509
510 # test if it is a postgres database cluster
511
512 if [ ! -f ${PGDATA}/postgresql.conf ]
513 then
514 # SCMSGS
515 # @explanation
516 # A directory is specified in the
517 # PGDATA variable which does not
518 # contain a postgresql.conf file.
519 # @user_action
520 # Specify a directory in the PGDATA
521 # variable in the parmeter file, which
522 # contains the postgresql.conf file.
523 scds_syslog -p daemon.err -t $(syslog_tag) -m \
524 "Function: validate: Directory %s does not contain the PostgreSQL configuration files" \
525 "${PGDATA}"
526 rc_validate=1
527 else
528 debug_message "Function: validate - PGDATA OK"
529 fi
530 fi;;
531
532 PGPORT)
533
534 # Test the PG Port variable
535
536 if [ -z "${PGPORT}" ]; then
537 scds_syslog -p daemon.err -t $(syslog_tag) -m \
538 "Function: validate: The %s variable is not set, but it is required" \
539 "PGPORT"
540 rc_validate=1
541 else
542
543 # test if the port is numeric
544
545 if ! let x=${PGPORT} >/dev/null 2>&1
546 then
547 # SCMSGS
548 # @explanation
549 # In the parameter file, there is a
550 # non numeric character in the value
551 # for the PGPORT variable.
552 # @user_action
553 # Fix the PGPORT variable in the
554 # parameter file.
555 scds_syslog -p daemon.err -t $(syslog_tag) -m \
556 "Function: validate: Port %s is not numeric" \
557 "${PGPORT}"
558 rc_validate=1
559 else
560 debug_message "Function: validate - PGPORT OK"
561 fi
562 fi;;
563
564 PGHOST)
565
566 # test the PGHOST variable ony if it is defined
567
568 if [ -n "${PGHOST}" ]
569 then
570
571 # strip of leading spaces
572
573 PGHOST=`print ${PGHOST}|${SED} 's/^ *//'`
574
575 if ${ECHO} ${PGHOST} | ${GREP} "^/" >/dev/null 2>&1
576 then
577
578 if [ ! -d "${PGHOST}" ]
579 then
580
581 # SCMSGS
582 # @explanation
583 # The directory specified in the PGHOST variable does not
584 # exist.
585 # @user_action
586 # Create the directory. None if it was a lost mount.
587 scds_syslog -p daemon.err -t $(syslog_tag) -m \
588 "Function: validate - Directory for the socket file %s does not exist" \
589 "${PGHOST}"
590 rc_validate=1
591
592 else
593 debug_message "Function: validate - PGHOST OK"
594 fi
595
596 else
597 if ! ${GETENT} hosts ${PGHOST} >/dev/null 2>&1
598 then
599
600 # SCMSGS
601 # @explanation
602 # The host specified in the PGHOST variable is not
603 # resolvable.
604 # @user_action
605 # Create the the host entry in /etc/hosts.
606 scds_syslog -p daemon.err -t $(syslog_tag) -m \
607 "Function: validate - The host %s is not resolvable" \
608 "${PGHOST}"
609 rc_validate=1
610
611 else
612 debug_message "Function: validate - PGHOST resolvable"
613 fi
614
615 # Validate if the address of the PGHOST variable is configured UP
616 # on a adapter of the host. This validation works in
617 # global zones, local zones and in failover zones.
618 # This method was preferred over checking the dependency tree,
619 # because it works in failover zones, even if there is no logical
620 # host configured.
621
622 # Set the laguage to C to avoid localisation problems with ifconfig
623
624 LANG=C
625
626 addr=`${GETENT} hosts ${PGHOST}| ${AWK} '{print $1}'`
627
628 # Check if the address is configured up on the node
629
630 adapter_success=1
631 for i in `${IFCONFIG} -a |${GREP} UP|${AWK} '{print $1}' |${EGREP} -v "zone|inet"|${GREP} ":$"|${SED} s/:$//`
632 do
633
634 ${IFCONFIG} ${i}|${GREP} ${addr} >/dev/null 2>&1
635 if [ ${?} -eq 0 ]
636 then
637 adapter_success=0
638 fi
639
640 done
641
642 if [ ${adapter_success} -ne 0 ]
643 then
644
645 # SCMSGS
646 # @explanation
647 # The host specified in the PGHOST variable is not
648 # configured up on the hosts adapters.
649 # @user_action
650 # Fix either the network configuration or the PGHOST variable
651 scds_syslog -p daemon.err -t $(syslog_tag) -m \
652 "Function: validate - The host %s is not configured UP on the hosts adapters" \
653 "${PGHOST}"
654 rc_validate=1
655 else
656 debug_message "Function: validate - PGHOST is configured on the nodes adapters"
657 fi
658 fi
659 fi;;
660
661 PGLOGFILE)
662
663 # Test the Logfile variable
664
665 if [ -z "${PGLOGFILE}" ]; then
666 scds_syslog -p daemon.err -t $(syslog_tag) -m \
667 "Function: validate: The %s variable is not set, but it is required" \
668 "PGLOGFILE"
669 rc_validate=1
670 else
671
672 # test if the directory for Logfile exists
673
674 Logdir=`/usr/bin/dirname ${PGLOGFILE}`
675 if [ ! -d ${Logdir} ]; then
676 # SCMSGS
677 # @explanation
678 # The path to the filename variable
679 # PGLOGFILE does not exist.
680 # @user_action
681 # Qualify the filename of the parameter
682 # files PGLOGFILE variable in an
683 # existing directory.
684 scds_syslog -p daemon.err -t $(syslog_tag) -m \
685 "Function: validate: Directory for logfile %s does not exist, an existing directory is required" \
686 "${PGLOGFILE}"
687 rc_validate=1
688 else
689 debug_message "Function: validate - PGLOGFILE OK"
690 fi
691 fi;;
692
693 LD_LIBRARY_PATH)
694
695 # test LD_LIBRARY_PATH if it is set
696
697 if [ -n "${LD_LIBRARY_PATH}" ]
698 then
699 export LD_LIBRARY_PATH
700 if ! ${PGROOT}/bin/psql --help >/dev/null 2>&1
701 then
702 # SCMSGS
703 # @explanation
704 # The LD_LIBRARY_PATH is not valid to
705 # call the postgres binary.
706 # @user_action
707 # Qualify the LD_LIBRARY_PATH in the
708 # parameter file until it is
709 # sufficient for the psql binary.
710 scds_syslog -p daemon.err -t $(syslog_tag) -m \
711 "Function: validate: The LD_LIBRARY_PATH %s is not valid for this PostgreSQL installation" \
712 "${LD_LIBRARY_PATH}"
713 rc_validate=1
714 else
715 debug_message "Function: validate - LD_LIBRARY_PATH OK"
716 fi
717 fi;;
718
719 ENVSCRIPT)
720
721 # test if the environment script is a syntactically valid script
722 # In the smf context it needs to be a ksh script.
723 # In the GDS context the script type ksh/csh is dependent from the login shell of the user.
724
725 if [ -n "${ENVSCRIPT}" ]
726 then
727 if [ -f ${ENVSCRIPT} ]
728 then
729 if ${GETENT} passwd ${USER} | ${AWK} -F: '{print $7}' | ${GREP} "csh" > /dev/null && [ -z "${SMF_FMRI}" ]
730 then
731 if ! /usr/bin/csh -n ${ENVSCRIPT} > /dev/null 2>&1
732 then
733 # SCMSGS
734 # @explanation
735 # The environment
736 # script spcified in
737 # the parameter file
738 # needs to be a valid
739 # c shell script,
740 # because the login
741 # shell of the
742 # PostgreSQL user is c
743 # shell compliant.
744 # @user_action
745 # Fix the environment
746 # script until it
747 # passes csh -n
748 # scriptname.
749 scds_syslog -p daemon.err -t $(syslog_tag) -m \
750 "Function: validate: The Environment script %s is not a valid c shell script" \
751 "${ENVSCRIPT}"
752 rc_validate=1
753 else
754 debug_message "Function: validate - ENVSCRIPT OK"
755 fi
756 else
757 if ! /usr/bin/ksh -n ${ENVSCRIPT} >/dev/null 2>&1
758 then
759 # SCMSGS
760 # @explanation
761 # The environment
762 # script spcified in
763 # the parameter file
764 # needs to be a valid
765 # korn shell script,
766 # because the login
767 # shell of the
768 # PostgreSQL user is
769 # korn shell
770 # compliant.
771 # @user_action
772 # Fix the environment
773 # script until it
774 # passes ksh -n
775 # scriptname.
776 scds_syslog -p daemon.err -t $(syslog_tag) -m \
777 "Function: validate: The Environment script %s is not a valid korn shell script" \
778 "${ENVSCRIPT}"
779 rc_validate=1
780 else
781 debug_message "Function: validate - ENVSCRIPT OK"
782 fi
783 fi
784 else
785 # SCMSGS
786 # @explanation
787 # The filename specified in the
788 # parameter files ENVSCRIPT variable
789 # does not exist.
790 # @user_action
791 # Fix the parameter file and specify a
792 # valid Environment script.
793 scds_syslog -p daemon.err -t $(syslog_tag) -m \
794 "Function: validate: The Environment script %s does not exist" \
795 "${ENVSCRIPT}"
796 rc_validate=1
797
798 fi
799 fi;;
800
801 SCDB)
802
803 # Test if the test database variable is defined
804
805 if [ -z "${SCDB}" ]; then
806 scds_syslog -p daemon.err -t $(syslog_tag) -m \
807 "Function: validate: The %s variable is not set, but it is required" \
808 "SCDB"
809 rc_validate=1
810 else
811 debug_message "Function: validate - SCDB OK"
812 fi;;
813
814 SCUSER)
815
816 # Test if the database user variable is defined
817
818 if [ -z "${SCUSER}" ]; then
819 scds_syslog -p daemon.err -t $(syslog_tag) -m \
820 "Function: validate: The %s variable is not set, but it is required" \
821 "SCUSER"
822 rc_validate=1
823 else
824 debug_message "Function: validate - SCUSER OK"
825 fi;;
826
827 SCTABLE)
828
829 # Test if the database table variable is defined
830
831 if [ -z "${SCTABLE}" ]; then
832 scds_syslog -p daemon.err -t $(syslog_tag) -m \
833 "Function: validate: The %s variable is not set, but it is required" \
834 "SCTABLE"
835 rc_validate=1
836 else
837 debug_message "Function: validate - SCTABLE OK"
838 fi;;
839
840 NOCONRET)
841
842 # Test the No Connection return code variable
843
844 if [ -z "${NOCONRET}" ]; then
845 scds_syslog -p daemon.err -t $(syslog_tag) -m \
846 "Function: validate: The %s variable is not set, but it is required" \
847 "NOCONRET"
848 rc_validate=1
849 else
850
851 # test if the NOCONRET is numeric
852
853 if ! let x=${NOCONRET} >/dev/null 2>&1
854 then
855 # SCMSGS
856 # @explanation
857 # The value for the NOCONRET variable
858 # contains a non numeric character.
859 # @user_action
860 # Fix the NOCONRET variable in the
861 # parameter file.
862 scds_syslog -p daemon.err -t $(syslog_tag) -m \
863 "Function: validate: Return code for failed connections %s is not numeric" \
864 "${NOCONRET}"
865 rc_validate=1
866 else
867 if [ ${NOCONRET} -gt 100 ]; then
868 # SCMSGS
869 # @explanation
870 # The value of the NOCONRET
871 # variable in the parameter
872 # file exeeds 100.
873 # @user_action
874 # Fix the parameter file with
875 # a value below 100.
876 scds_syslog -p daemon.err -t $(syslog_tag) -m \
877 "Function: validate: Return code for failed connections %s is greater 100" \
878 "${NOCONRET}"
879 rc_validate=1
880 else
881 debug_message "Function: validate - NOCONRET OK"
882 fi
883 fi
884 fi;;
885
886 STDBY_HOST)
887
888 # Test the standby host variable and the neccessary other variables if the standby
889 # host variable is not set.
890
891 if [ -n "${STDBY_HOST}" ]; then
892 if ! ${GETENT} hosts ${STDBY_HOST} >/dev/null 2>&1
893 then
894
895 # SCMSGS
896 # @explanation
897 # The host specified in the STDBY_HOST variable is not
898 # resolvable.
899 # @user_action
900 # Add the host to one of your configured name services,
901 # so it can get listed with getent.
902 scds_syslog -p daemon.err -t $(syslog_tag) -m \
903 "Function: validate - The standby host %s is not resolvable" \
904 "${STDBY_HOST}"
905 rc_validate=1
906
907 else
908 debug_message "Function: validate - STDBY_HOST resolvable"
909 fi
910
911 # Test if all the other standby related variables are set.
912 # There will be no other validation, because it may be that the necessary
913 # resources are not up right now, and then the validation will fail without
914 # a valid reason which is related to the parameter configuration.
915
916 if [ -z "${STDBY_RS}" ]
917 then
918 scds_syslog -p daemon.err -t $(syslog_tag) -m \
919 "Function: validate: The %s variable is not set, but it is required" \
920 "STDBY_RS"
921 rc_validate=1
922 else
923 debug_message "Function: validate - STDBY_RS OK"
924 fi
925
926 if [ -z "${STDBY_RG}" ]
927 then
928 scds_syslog -p daemon.err -t $(syslog_tag) -m \
929 "Function: validate: The %s variable is not set, but it is required" \
930 "STDBY_RG"
931 rc_validate=1
932 else
933 debug_message "Function: validate - STDBY_RG OK"
934 fi
935
936 if [ -z "${STDBY_USER}" ]
937 then
938 scds_syslog -p daemon.err -t $(syslog_tag) -m \
939 "Function: validate: The %s variable is not set, but it is required" \
940 "STDBY_USER"
941 rc_validate=1
942 else
943 debug_message "Function: validate - STDBY_USER OK"
944 fi
945
946 if [ -z "${STDBY_PARFILE}" ]
947 then
948 scds_syslog -p daemon.err -t $(syslog_tag) -m \
949 "Function: validate: The %s variable is not set, but it is required" \
950 "STDBY_PARFILE"
951 rc_validate=1
952 else
953 debug_message "Function: validate - STDBY_PARFILE OK"
954 fi
955
956 if [ -n "${STDBY_PING}" ]
957 then
958 if ! let x=${STDBY_PING} >/dev/null 2>&1
959 then
960 scds_syslog -p daemon.err -t $(syslog_tag) -m \
961 "Function: validate: The STDBY_PING value of %s is not numeric" \
962 "${STDBY_PING}"
963 rc_validate=1
964 else
965 debug_message "Function: validate - STDBY_PING OK"
966 fi
967 else
968 # set a default of 5 packets
969 STDBY_PING=5
970 debug_message "Function: validate - STDBY_PING OK, it was set to 5 packets"
971 fi
972
973 fi;;
974 esac
975 done
976
977 debug_message "Function: validate - End"
978 return ${rc_validate}
979 }
980
981 validate_probe()
982 {
983 # Validate ony for non existant files or lost directories
984
985 debug_message "Function: validate_probe - Begin"
986 ${SET_DEBUG}
987
988 rc_val_probe=0
989
990 # If the parameter file does not pass the short validation, try a failover
991 # A failover is the appropriate action, because the directory existed
992 # at startup of the resource.
993
994 if ! val_parfile ${PARFILE}
995 then
996
997
998 # SCMSGS
999 # @explanation
1000 # The file specified in the PARFILE variable does not
1001 # exist any more.
1002 # @user_action
1003 # Create the directory and restore the parameter file. None if it was a lost mount.
1004 scds_syslog -p daemon.err -t $(syslog_tag) -m \
1005 "Function: validate_probe - Directory for the parameter file %s does not exist any more, a faiover will occur" \
1006 "${PARFILE}"
1007
1008 rc_val_probe=201
1009 fi
1010
1011 # source the parameter file
1012
1013 . ${PARFILE}
1014
1015 # Check the PGHOST variable.
1016 # If the PGHOST variable starts with a / then it should be a directory which contains the socket file.
1017 # If this directory is not available, a failover will be initiated.
1018 # If it does not contain a / then it has to be a hostname or an address, in this case the hostname
1019 # has to respond to ping.
1020
1021 if [ -n "${PGHOST}" ]
1022 then
1023
1024 # strip of leading spaces
1025
1026 PGHOST=`print ${PGHOST}|${SED} 's/^ *//'`
1027
1028 if ${ECHO} ${PGHOST} | ${GREP} "^/" >/dev/null 2>&1
1029 then
1030
1031 if [ ! -d "${PGHOST}" ]
1032 then
1033
1034 # SCMSGS
1035 # @explanation
1036 # The directory specified in the PGHOST variable does not
1037 # exist any more.
1038 # @user_action
1039 # Create the directory. None if it was a lost mount.
1040 scds_syslog -p daemon.err -t $(syslog_tag) -m \
1041 "Function: validate_probe - Directory for the socket file %s does not exist any more, a faiover will occur" \
1042 "${PGHOST}"
1043 rc_val_probe=201
1044 else
1045 debug_message "Function: validate_probe - the directory in PGHOST exists"
1046 fi
1047
1048 else
1049
1050 # If an address is specified, test it with ping. Initiate a failover if the address
1051 # is unavailable.
1052 # This needs to be done, because an unpingable address will cause the psql commands to hang
1053 # The test will detect accidentally unconfigured interfaces, just a failover or restart of
1054 # the resource group can cure this problem.
1055
1056 # This ping test is here to prevent a predictable timeout, it is needed as long as
1057 # SUNW.LogicalHost does not probe the ipaddresses. As soon as this changes the
1058 # ping test should be removed.
1059
1060 if ! ${PING} ${PGHOST} 1 >/dev/null 2>&1
1061 then
1062 # SCMSGS
1063 # @explanation
1064 # The address specified in the PGHOST variable
1065 # is unavailable.
1066 # @user_action
1067 # None, a failover will occur
1068 scds_syslog -p daemon.err -t $(syslog_tag) -m \
1069 "check_pgs: The host %s is not accessible, a failover will occur" \
1070 "${PGHOST}"
1071
1072 rc_val_probe=201
1073 else
1074 debug_message "Function: validate_probe - the host in PGHOST is pingable"
1075 fi
1076 fi
1077 fi
1078
1079 debug_message "Function: validate_probe - End"
1080 return $rc_val_probe
1081 }
1082
1083 val_parfile()
1084 {
1085 # Common valdation for parameter file
1086 #
1087 # If the parameter is in $2, there will be an intensive validation.
1088 # If $2 is empty, the validation will just check for the existance of the file.
1089
1090 debug_message "Function: val_parfile - Begin"
1091 ${SET_DEBUG}
1092
1093 rc_val_parfile=0
1094
1095 # Validate that parameter file exists
1096
1097 PARFILE=${1}
1098 PARLIST=${2}
1099
1100 if [ ! -f "${PARFILE}" ]; then
1101 # SCMSGS
1102 # @explanation
1103 # The parameter file does not exist in the parameter file
1104 # directory.
1105 # @user_action
1106 # Restore the parameter file or re-register the resource.
1107 scds_syslog -p daemon.err -t $(syslog_tag) -m \
1108 "Function: val_parfile - File %s does not exist" \
1109 "${PARFILE}"
1110 rc_val_parfile=1
1111 else
1112 debug_message "Function: val_parfile - ${PARFILE} exists"
1113 fi
1114
1115 # Test the semantics only, if the parameter list is specified.
1116 # This should not be done when called from validate_probe.
1117
1118 if [ -n "${2}" ]
1119 then
1120
1121 # Test if the parameter file is a valid ksh script
1122
1123 if ! ksh -n ${PARFILE} >/dev/null 2>&1
1124 then
1125 # SCMSGS
1126 # @explanation
1127 # The parameter file is not a valid shell script.
1128 # @user_action
1129 # Correct the parameter file. It must pass ksh -n <file name>.
1130 scds_syslog -p daemon.err -t $(syslog_tag) -m \
1131 "Function: validate - Syntax errors in %s" \
1132 "${PARFILE}"
1133 rc_val_parfile=1
1134 else
1135 debug_message "Function: val_parfile - validated ${PARFILE}"
1136 fi
1137
1138 # Test if all the mandatory variables are included and set correctly in the parameter file
1139
1140 PARAMETERS=`${CAT} ${PARFILE} |grep -v "^#"|grep -v "^ "|nawk -F= '{print $1}'`
1141
1142 for i in ${PARLIST}
1143 do
1144 if ! `echo ${PARAMETERS} |grep ${i} > /dev/null `; then
1145 # SCMSGS
1146 # @explanation
1147 # The referenced necessary parameter is not mentioned
1148 # in the parameter file.
1149 # @user_action
1150 # Specify the parameter as a key value pair in the
1151 # parameter file.
1152 scds_syslog -p daemon.err -t $(syslog_tag) -m \
1153 "Function: val_parfile - %s not specified in %s, which is required" \
1154 "${i}" "${PARFILE}"
1155 rc_val_parfile=1
1156 else
1157 debug_message "Function: val_parfile - ${i} included in ${PARFILE}"
1158 fi
1159 done
1160 fi
1161
1162 debug_message "Function: val_parfile - End"
1163 return ${rc_val_parfile}
1164 }
1165
1166
1167 Remove_shared_memory()
1168 {
1169 debug_message "Function: Remove_shared_memory - Start called with the following arguments "$*
1170 ${SET_DEBUG}
1171
1172 User=$1
1173
1174 if [ -n "${DEBUG}" ]
1175 then
1176 debug_message "IPC Status of the current zone BEFORE removal of non-attached segments created by user ${User}"
1177
1178 # remove the logfile, before creating it to survive potential noclobber settings
1179
1180 ${RM} ${LOGFILE} 2>/dev/null
1181 ${IPCS} -mcopb > ${LOGFILE}
1182
1183 log_message debug ipcs
1184 ${RM} ${LOGFILE}
1185 fi
1186
1187 ${IPCS} -mcopb |${GREP} " ${User} "| ${AWK} ' \
1188 {if (NF == 12 && $9 == 0 ) print $2,$5,$6,$11,$12; else \
1189 if (NF == 11 && $8 == 0 ) print $1,$4,$5,$10,$11 }' | \
1190 while read SHMID SHMUSER GROUP CPID LPID
1191 do
1192 if ${PS} -p ${CPID} > /dev/null
1193 then
1194 debug_message "PostgresSQL SHMID: ${SHMID} - CPID ${CPID} is running"
1195 else
1196 if ${PS} -p ${LPID} > /dev/null
1197 then
1198 debug_message "PostgresSQL SHMID: ${SHMID} - LPID ${LPID} is running"
1199 else
1200 SHMID=`${ECHO} ${SHMID} | ${TR} 'm' ' '`
1201 ${IPCRM} -m ${SHMID} > /dev/null
1202 debug_message "PostgreSQL SHMID: ${SHMID} - removed"
1203 flag=deleted
1204 fi
1205 fi
1206 done
1207
1208 if [ "${flag}" ]; then
1209 # SCMSGS
1210 # @explanation
1211 # Remaining IPC shared memory segments have been removed.
1212 # These segements are a leftover of the previous PostgreSQL
1213 # instance.
1214 # @user_action
1215 # None
1216 scds_syslog -p daemon.notice -t $(syslog_tag) -m \
1217 "All PostgreSQL non-attached IPC shared memory segments removed"
1218 fi
1219
1220 if [ -n "${DEBUG}" ]
1221 then
1222 debug_message "IPC Status AFTER removal of non-attached segments created by user ${User}"
1223
1224 ${IPCS} -mcopb > ${LOGFILE}
1225
1226 log_message debug ipcs
1227 $RM ${LOGFILE}
1228 fi
1229
1230 debug_message "Function: Remove_shared_memory - End"
1231 }
1232
1233 start_pgs()
1234 {
1235 #
1236 # Start PostgreSQL
1237 #
1238
1239 debug_message "Function: start_pgs - Begin"
1240 ${SET_DEBUG}
1241 SECONDS=0
1242
1243 # construct the necessary redirection and source variables
1244
1245 set_shell_specifics
1246
1247 # Define the appropriate newtask command.
1248 # The Project will be derived according to the call method,
1249 # either from the smf service or from the cluster resource / resource group
1250
1251 srm_function ${USER}
1252
1253 # remove shared memory which may be there from a killed postmaster
1254
1255 Remove_shared_memory ${USER}
1256
1257 # construct the necessary environment variables
1258
1259 LIBPATH=
1260 if [ -n "${LD_LIBRARY_PATH}" ]
1261 then
1262 LIBPATH="${ENV} LD_LIBRARY_PATH=${LD_LIBRARY_PATH}"
1263 fi
1264
1265 PORT="PGPORT=${PGPORT}"
1266 DATA="PGDATA=${PGDATA}"
1267
1268 # remove the logfile, before creating it to survive potential noclobber settings
1269
1270 ${RM} ${LOGFILE} 2>/dev/null
1271
1272 do_start=0
1273
1274 # start an ssh-agent and store the decrypted private key if SSH_PASSDIR is configured
1275
1276
1277 if [ -n "${SSH_PASSDIR}" ]
1278 then
1279
1280 ${CP} -p ${SSH_PASSDIR}/${RESOURCE}-phrase /tmp/${RESOURCE}-phrase
1281
1282 if [ -z "${SMF_FMRI}" ]
1283 then
1284 ${CHOWN} ${USER} /tmp/${RESOURCE}-phrase
1285 ${SU} ${USER} -c " ${TASK_COMMAND} ${MYDIR}/${MYNAME} -R ${RESOURCE} -G ${RESOURCEGROUP} -P ${PARFILE} start_ssh_agent "> /dev/null 2>&1
1286 if [ ${?} -ne 0 ]
1287 then
1288 do_start=1
1289 fi
1290 else
1291 ${MYDIR}/${MYNAME} -R ${RESOURCE} -G ${RESOURCEGROUP} -P ${PARFILE} start_ssh_agent > /dev/null 2>&1
1292 if [ ${?} -ne 0 ]
1293 then
1294 do_start=1
1295 fi
1296 fi
1297
1298 ${RM} /tmp/${RESOURCE}-phrase
1299
1300
1301 # store the SSH_AUTH_SOCK value in the SOCK variable
1302
1303 SOCK=
1304 if [ ${do_start} -eq 0 ]
1305 then
1306 SOCK=`${GREP} SSH_AUTH_SOCK /tmp/${RESOURCE}-ssh`
1307 SOCK="${ENV} ${SOCK}"
1308 fi
1309 fi
1310
1311 # If a standby host is configured, check if the standby host is available and configured/acting
1312 # as a standby. If everything is ok continue with the startup. If not, do not start the PostgreSQL
1313 # resource.
1314
1315 if [ -n "${STDBY_HOST}" ] && [ ${do_start} -eq 0 ]
1316 then
1317
1318 if ${PING} ${STDBY_HOST} ${STDBY_PING} >/dev/null 2>&1
1319 then
1320 debug_message "Function: start_pgs - the host ${STDBY_HOST} is accessible"
1321
1322 # As the PostgreSQL user perform a check on the standby host, to determine if it
1323 # is configured as a primary, it runs as a primary, or it runs as a standby database.
1324
1325 if [ -z "${SMF_FMRI}" ]
1326 then
1327
1328 ${SU} ${USER} -c " ${TASK_COMMAND} ${SOCK} ${SSH} ${STDBY_USER}@${STDBY_HOST} ${MYDIR}/${MYNAME} -R ${STDBY_RS} -G ${STDBY_RG} -P ${STDBY_PARFILE} check_stdby "> /dev/null 2>&1
1329 if [ ${?} -ne 0 ]
1330 then
1331 do_start=1
1332 fi
1333 else
1334 ${SOCK} ${SSH} ${STDBY_USER}@${STDBY_HOST} ${MYDIR}/${MYNAME} -R ${STDBY_RS} -G ${STDBY_RG} -P ${STDBY_PARFILE} check_stdby ${OUTPUT} >/dev/null 2>&1
1335 if [ ${?} -ne 0 ]
1336 then
1337 do_start=1
1338 fi
1339
1340 fi
1341 if [ $do_start -ne 0 ]
1342 then
1343 # SCMSGS
1344 # @explanation
1345 # The PostgreSQL resource on the standby host is not
1346 # configured as a standby or acting as a primary.
1347 # @user_action
1348 # Consult the logs on the standby host and insure, that
1349 # the standby host is configured as a standby database,
1350 # if it is running as a primary, reconfigure and restart it.
1351 scds_syslog -p daemon.err -t $(syslog_tag) -m \
1352 "Function: start_pgs - resource %s on host %s is not configured/running as a standby database" \
1353 "${STDBY_RS}" "${STDBY_HOST}"
1354 else
1355 debug_message "Function: start_pgs - the resource ${STDBY_RS} on host ${STDBY_HOST} is configured/running as a standby database"
1356 fi
1357
1358 else
1359 # SCMSGS
1360 # @explanation
1361 # The standby host is not up and running.
1362 # @user_action
1363 # Consult the logs on the standby host and insure, that
1364 # the standby host is answering on ping requests of the primary host.
1365 scds_syslog -p daemon.err -t $(syslog_tag) -m \
1366 "Function: start_pgs - the standby host %s is not answering on ping" \
1367 "${STDBY_HOST}"
1368 do_start=1
1369 fi
1370 fi
1371
1372 # continue on the start process
1373
1374 if [ ${do_start} -eq 0 ]
1375 then
1376
1377 # Start PostgreSql, the postmaster searches for databases in the directory of the PGDATA variable,
1378 # and it will listen on the port of the PGORT varaible. The logfile will be stored in the file name
1379 # contained in the PGLOGFILE variable.
1380 # The postmaster is started via the pg_ctl utility.
1381 #
1382
1383 if [ -z "${SMF_FMRI}" ]
1384 then
1385 ${SU} ${USER} -c " ${ENVSC} ${TASK_COMMAND} ${SOCK} ${LIBPATH} ${ENV} ${DATA} ${ENV} ${PORT} ${PGROOT}/bin/pg_ctl start -l ${PGLOGFILE} ${OUTPUT}" > /dev/null
1386 rc_start_command=$?
1387 else
1388
1389 # start under the right user in an smf manifest you source a ksh script, regardless of the users login shell
1390
1391 if [ -n "${ENVSCRIPT}" ]
1392 then
1393 . ${ENVSCRIPT}
1394 fi
1395
1396 ${SOCK} ${LIBPATH} ${ENV} ${DATA} ${ENV} ${PORT} ${PGROOT}/bin/pg_ctl start -l ${PGLOGFILE} >${LOGFILE} 2>&1
1397 rc_start_command=$?
1398 fi
1399
1400 # if an ssh-agent was started, remember the postmaster pid in /tmp/${RESOURCE}-pid
1401
1402 if [ -n "${SOCK}" ] && [ ${rc_start_command} -eq 0 ]
1403 then
1404 START_TIMEOUT=`${SCHA_RESOURCE_GET} -O START_TIMEOUT -R ${RESOURCE} -G ${RESOURCEGROUP}`
1405 MAX_START=`expr ${START_TIMEOUT} \* 70 \/ 100`
1406
1407 # give PostgreSQL a chance to construct the ${PGDATA}/postmaster pid, it is
1408 # done asynchronously
1409
1410 PID_LINES=0
1411 while [ ${SECONDS} -lt ${MAX_START} ] && [ ${PID_LINES} -eq 0 ]
1412 do
1413 if [ -f ${PGDATA}/postmaster.pid ]
1414 then
1415 PID_LINES=`${WC} -l ${PGDATA}/postmaster.pid|${AWK} '{print $1}'`
1416 fi
1417 ${SLEEP} 2
1418 done
1419
1420 ${RM} /tmp/${RESOURCE}-pid 2>/dev/null
1421 ${HEAD} -1 ${PGDATA}/postmaster.pid >/tmp/${RESOURCE}-pid
1422 fi
1423 else
1424 rc_start_command=1
1425
1426 # disable the pmf tag and run a sleep in the background, to assure, that there will be a valid pmftag during the start phase
1427
1428 START_TIMEOUT=`${SCHA_RESOURCE_GET} -O START_TIMEOUT -R ${RESOURCE} -G ${RESOURCEGROUP}`
1429 sleep ${START_TIMEOUT} &
1430 ${PMFADM} -s ${RESOURCEGROUP},${RESOURCE},0.svc
1431
1432 # As a workaround until RFE 6629606 is implemented, kill the gds_svc start method
1433 # to speed up the transition into START_FAILED.
1434 # If gds_svc_start gets killed the resource transition into START_FAILED and does not
1435 # wait until the start_timeout expires.
1436
1437 ${PKILL} -u root -f "gds_svc_start .*-R ${RESOURCE} " >/dev/null
1438 fi
1439
1440 debug_message "Function: start_pgs - End"
1441 return ${rc_start_command}
1442 }
1443
1444 stop_pgs()
1445 {
1446 #
1447 # Stop PostgreSQL
1448 #
1449
1450 debug_message "Function: stop_pgs - Begin"
1451 ${SET_DEBUG}
1452
1453 # construct the necessary redirection and source variables
1454
1455 set_shell_specifics
1456
1457 # Define the appropriate newtask command.
1458 # The Project will be derived according to the call method,
1459 # either from the smf service or from the cluster resource / resource group
1460
1461 srm_function ${USER}
1462
1463 # construct the necessary environment variables
1464
1465 LIBPATH=
1466 if [ -n "${LD_LIBRARY_PATH}" ]
1467 then
1468 LIBPATH="${ENV} LD_LIBRARY_PATH=${LD_LIBRARY_PATH}"
1469 fi
1470
1471 PORT="PGPORT=${PGPORT}"
1472 DATA="PGDATA=${PGDATA}"
1473
1474 # remember the process id of the parent postmaster
1475
1476 pgrspid=`${HEAD} -1 ${PGDATA}/postmaster.pid`
1477
1478 # remove the logfile, before creating it to survive potential noclobber settings
1479
1480 ${RM} ${LOGFILE} 2>/dev/null
1481
1482 # Perform a fast shutdown first. The server is specified by the triple user, PGPORT and the PGDATA variable.
1483 # The fast shutdown will disconnect the clients and stop the server processes.
1484
1485 # SCMSGS
1486 # @explanation
1487 # The PostgreSQL database server is shut down with the specified
1488 # option.
1489 # @user_action
1490 # None
1491 scds_syslog -p daemon.notice -t $(syslog_tag) -m \
1492 "stop_pgs: Stop PostgreSQL with the option %s " \
1493 "fast"
1494
1495 if [ -z "${SMF_FMRI}" ]
1496 then
1497 ${SU} ${USER} -c " ${ENVSC} ${TASK_COMMAND} ${LIBPATH} ${ENV} ${DATA} ${ENV} ${PORT} ${PGROOT}/bin/pg_ctl stop -m fast ${OUTPUT}" > /dev/null
1498 rc_stop_command=$?
1499 else
1500
1501 # stop under the right user in a smf manifest
1502
1503 if [ -n "${ENVSCRIPT}" ]
1504 then
1505 . ${ENVSCRIPT}
1506 fi
1507
1508 ${LIBPATH} ${ENV} ${DATA} ${ENV} ${PORT} ${PGROOT}/bin/pg_ctl stop -m fast >${LOGFILE} 2>&1
1509 rc_stop_command=$?
1510 fi
1511
1512 # Determine if postgres is really stopped, if not perform an immediate shutdown.
1513 # The server is specified by the triple user, PGPORT and the PGDATA variable.
1514 # The immediate shutdown stops the server processes without disconnecting the clients.
1515 # The immediate shutdown will be performd only, if the postgres database is not configured as
1516 # a standby database, because then an immediate shutdown will not succeed in a standby configuration.
1517
1518
1519 if [ ! -f ${PGDATA}/recovery.conf ]
1520 then
1521 if ${PS} -u ${USER} -o pid,ppid |${GREP} -w ${pgrspid}>/dev/null
1522 then
1523
1524 scds_syslog -p daemon.notice -t $(syslog_tag) -m \
1525 "stop_pgs: Stop PostgreSQL with the option %s " \
1526 "immediate"
1527
1528 if [ -z "${SMF_FMRI}" ]
1529 then
1530 ${SU} ${USER} -c "${ENVSC} ${TASK_COMMAND} ${LIBPATH} ${ENV} ${DATA} ${ENV} ${PORT} ${PGROOT}/bin/pg_ctl stop -m immediate ${OUTPUT_APP}" > /dev/null
1531 rc_stop_command=$?
1532 else
1533
1534 # stop under the right user in a smf manifest
1535
1536 if [ -n "${ENVSCRIPT}" ]
1537 then
1538 . ${ENVSCRIPT}
1539 fi
1540
1541 ${LIBPATH} ${ENV} ${DATA} ${ENV} ${PORT} ${PGROOT}/bin/pg_ctl stop -m immediate >>${LOGFILE} 2>&1
1542 rc_stop_command=$?
1543 fi
1544 fi
1545 else
1546 debug_message "Function: stop_pgs - It is a standby database, do not stop with immediate"
1547 fi
1548
1549 # determine if postgres is really stopped, if not kill the parent of the postmaster with -9
1550
1551 if ${PS} -u ${USER} -o pid,ppid |${GREP} -w ${pgrspid}>/dev/null
1552 then
1553 # SCMSGS
1554 # @explanation
1555 # The previous stop attempts for PostgreSQL failed. The server
1556 # is now killed with kill -9.
1557 # @user_action
1558 # None
1559 scds_syslog -p daemon.notice -t $(syslog_tag) -m \
1560 "stop_pgs: Stop PostgreSQL process %s with kill -9 " \
1561 "${pgrspid}"
1562
1563 ${KILL} -9 ${pgrspid}
1564 rc_stop_command=$?
1565 fi
1566
1567 if [ -n "${SSH_PASSDIR}" ]
1568 then
1569 # stop the ssh-agent
1570
1571 SSH_PID=
1572 if [ -f /tmp/${RESOURCE}-ssh ]
1573 then
1574 debug_message "Function: stop_pgs - stop the ssh agent"
1575
1576 # source /tmp/${RESOURCE}-ssh to get the variable SSH_AGENT_PID
1577
1578 . /tmp/${RESOURCE}-ssh
1579
1580 SSH_PID="${ENV} SSH_AGENT_PID=${SSH_AGENT_PID}"
1581
1582 if [ -z "${SMF_FMRI}" ]
1583 then
1584 ${SU} ${USER} -c "${TASK_COMMAND} ${SSH_PID} ${SSH_AGENT} -k ${OUTPUT_APP}"
1585 rc_stop_command=$?
1586 else
1587 ${SSH_PID} ${SSH_AGENT} -k >>${LOGFILE}
1588 rc_stop_command=$?
1589 fi
1590
1591 # if the ssh-agent process is still there, kill it with -9
1592
1593 if ${PS} -p ${SSH_AGENT_PID} >/dev/null 2>&1
1594 then
1595 debug_message "Function: stop_pgs - The ssh-agent ${SSH_AGENT_PID} survived his stop request, kill it with -9"
1596 ${KILL} -9 ${SSH_AGENT_PID}
1597 fi
1598 else
1599 # SCMSGS
1600 # @explanation
1601 # It can not be determined which ssh agent is working for the user/database,
1602 # it is now killed by PMF using the configured stop signal.
1603 # @user_action
1604 # None
1605 scds_syslog -p daemon.notice -t $(syslog_tag) -m \
1606 "stop_pgs: Allow pmf to stop the remaining ssh-agent for the user %s" \
1607 "${USER}"
1608 fi
1609
1610 fi
1611
1612 debug_message "Function: stop_pgs - End"
1613 return ${rc_stop_command}
1614 }
1615
1616 check_pgs()
1617 {
1618 #
1619 # Probe PostgreSQL
1620 #
1621
1622 debug_message "Function: check_pgs - Begin"
1623 ${SET_DEBUG}
1624
1625 rc_check_command=0
1626
1627 # construct the necessary redirection and source variables
1628
1629 set_shell_specifics
1630
1631 # Define the appropriate newtask command.
1632 # The Project will be derived according to the call method,
1633 # either from the smf service or from the cluster resource / resource group
1634
1635 srm_function ${USER}
1636
1637 # determine the parent postmaster pid
1638
1639 pgrspid=""
1640 if [ -f ${PGDATA}/postmaster.pid ]
1641 then
1642 pgrspid=`${HEAD} -1 ${PGDATA}/postmaster.pid`
1643 else
1644
1645 # the pid store is created only if a ssh passphrase is defined
1646 # in this case get the pid from /tmp/${RESOURCE}-pid
1647
1648 if [ -n "${SSH_PASSDIR}" ]
1649 then
1650 pgrspid=`${CAT} /tmp/${RESOURCE}-pid`
1651 fi
1652 fi
1653
1654 # Determine if the gds start process is already completed, or the database start is far enough to allow connections
1655 # The criteria is the existence of the postmaster.pid file in the PGDATA directory.
1656 # As long as the GDS start is not complete, probe error messages will be suppressed.
1657
1658 wait_for_online=0
1659
1660 ${PGREP} -u root -f "gds_svc_start .*-R ${RESOURCE} " >/dev/null
1661 if [ ${?} -eq 0 ]
1662 then
1663 debug_message "Function: check_pgs - wait for online detected"
1664 wait_for_online=1
1665 if [ -n "${pgrspid}" ]
1666 then
1667 if ! ${PS} -u ${USER} -o pid,ppid |${GREP} -w ${pgrspid}>/dev/null
1668 then
1669 debug_message "Function: check_pgs - wait for online detected, postmaster is not running"
1670 rc_check_command=100
1671 else
1672 debug_message "Function: check_pgs - wait for online detected, postmaster is running proceed with normal checks"
1673 fi
1674 else
1675 debug_message "Function: check_pgs - wait for online detected, postmaster pid file ${PGDATA}/postmaster.pid not found"
1676 rc_check_command=100
1677 fi
1678 fi
1679
1680 # If a passphrase is defined a ssh agent is running together with the PostgreSQL deamon
1681 # each of the daemons satisfies pmf/smf, so we have to check manually for the processes to run.
1682 # If either the ssh-agent or the PostgreSQL daemons are not running, exit with 100.
1683 # This has to be done, because pmf/smf will not trigger a restart if only one of the process trees are gone.
1684
1685 if [ -n "${SSH_PASSDIR}" ] && [ -n "${pgrspid}" ]
1686 then
1687
1688 if ! ${PS} -u ${USER} -o pid,ppid |${GREP} -w ${pgrspid}>/dev/null
1689 then
1690 # SCMSGS
1691 # @explanation
1692 # The PostgreSQL process is not running.
1693 # @user_action
1694 # None
1695 scds_syslog -p daemon.err -t $(syslog_tag) -m \
1696 "check_pgs: The PostgreSQL process %s is not running" \
1697 "${pgrspid}"
1698 rc_check_command=100
1699 return ${rc_check_command}
1700
1701 fi
1702
1703 # Determine if the necessary ssh-agent is running. If PostgreSQL is running
1704 # without the ssh-agent, the replication is not working, so we have to return 100
1705
1706 if [ -f /tmp/${RESOURCE}-ssh ]
1707 then
1708
1709 sshpid=`${GREP} SSH_AGENT_PID /tmp/${RESOURCE}-ssh|${AWK} -F= '{print $2}'`
1710 if ! ${PS} -u ${USER} -o pid,ppid |${GREP} -w ${sshpid}>/dev/null
1711 then
1712 # SCMSGS
1713 # @explanation
1714 # The ssh-agent process associated with the PostgreSQL database
1715 # is not running.
1716 # @user_action
1717 # None
1718 scds_syslog -p daemon.err -t $(syslog_tag) -m \
1719 "check_pgs: The ssh-agent process %s is not running" \
1720 "${sshpid}"
1721 rc_check_command=100
1722 return ${rc_check_command}
1723 fi
1724
1725 else
1726
1727 # SCMSGS
1728 # @explanation
1729 # The file /tmp/<resourcename>-ssh containing the necessary information to manage
1730 # the ssh-agent together with the PostgreSQL database is unavailable.
1731 # @user_action
1732 # None
1733 scds_syslog -p daemon.err -t $(syslog_tag) -m \
1734 "check_pgs: The ssh-agent information file %s is unavailable" \
1735 "/tmp/${RESOURCE}-ssh"
1736 rc_check_command=100
1737 return ${rc_check_command}
1738
1739 fi
1740
1741 fi
1742
1743 # If there is no postmaster.pid during wait for online, or the database will not
1744 # accept updates, because it is configured as a standby database, terminate the probe.
1745 # To trigger an early exit of the probe, it is enough, that a recover.conf exists in $PGDATA.
1746 # So effectively the agent relies on process monitoring if a database is configured as a standby database.
1747
1748
1749 if [ ${rc_check_command} -ne 0 ] || [ -f ${PGDATA}/recovery.conf ]
1750 then
1751 debug_message "Function: check_pgs - End"
1752 return ${rc_check_command}
1753 fi
1754
1755 # construct the necessary environment variables
1756
1757 LIBPATH=
1758 if [ -n "${LD_LIBRARY_PATH}" ]
1759 then
1760 LIBPATH="${ENV} LD_LIBRARY_PATH=${LD_LIBRARY_PATH}"
1761 fi
1762
1763 # the variable PASSWORD is set to the database user login passowrd
1764
1765 PASSWORD=
1766 if [ -n "${SCPASS}" ]
1767 then
1768 PASSWORD="${ENV} PGPASSWORD=${SCPASS}"
1769 fi
1770 PORT="PGPORT=${PGPORT}"
1771 DATA="PGDATA=${PGDATA}"
1772
1773 if [ -n "${PGHOST}" ]
1774 then
1775 HOST="${ENV} PGHOST=${PGHOST}"
1776 fi
1777
1778 # remove the temporary output files before creating them to survive potential noclobber settings
1779
1780 ${RM} /tmp/${RESOURCE}-${USER}-cat-out 2>/dev/null
1781 ${RM} /tmp/${RESOURCE}-${USER}-cat-err 2>/dev/null
1782 ${RM} /tmp/${RESOURCE}-${USER}-tbl-out 2>/dev/null
1783 ${RM} /tmp/${RESOURCE}-${USER}-tbl-err 2>/dev/null
1784
1785 # construct the sql commands for the test
1786
1787 DBCAT="select datname from pg_database"
1788 DBTRUNC="truncate ${SCTABLE}"
1789 DBINS="insert into ${SCTABLE} (sccol) values('hello im there')"
1790 DBSEL="select * from ${SCTABLE}"
1791
1792 # check if the catalog of the postgres database is accessible
1793
1794 debug_message "Function: check_pgs - check if the database catalog is accessible with ${SCDB} "
1795
1796 ${SU} ${USER} -c "${OPEN_BRACKET} ${TASK_COMMAND} ${LIBPATH} $HOST ${PASSWORD} ${ENV} ${DATA} ${ENV} ${PORT} ${PGROOT}/bin/psql -d ${SCDB} -U ${SCUSER} -c \"${DBCAT}\" ${CAT_OUTPUT} ${CLOSE_BRACKET} ${CAT_ERRPUT} " >/dev/null
1797 rc_check_command=$?
1798
1799 # Return ${NOCONRET} if the connect fails, otherwise proceed with the check
1800
1801 if [ ${rc_check_command} -ne 0 ]
1802 then
1803
1804 debug_message "Function: check_pgs - connect to database ${SCDB} failed"
1805
1806 if [ ${wait_for_online} -eq 0 ]
1807 then
1808 cp /tmp/${RESOURCE}-${USER}-cat-err ${LOGFILE}
1809 log_message err "check_pgs: rc<${NOCONRET}>"
1810 fi
1811
1812 debug_message "Function: check_pgs - End"
1813 rc_check_command=${NOCONRET}
1814
1815 else
1816
1817 # check if the test database is in the database catalog
1818
1819 if ! ${EGREP} " ${SCDB}$| ${SCDB} " /tmp/${RESOURCE}-${USER}-cat-out >/dev/null 2>&1
1820 then
1821
1822 debug_message "Function: check_pgs - The test database ${SCDB} is not in the database catalog"
1823
1824 if [ ${wait_for_online} -eq 0 ]
1825 then
1826 # SCMSGS
1827 # @explanation
1828 # The database to monitor does not exist in
1829 # the database catalog.
1830 # @user_action
1831 # Fix the parameter file to contain the right
1832 # database name in the SCDB variable, or
1833 # prepare the database.
1834 scds_syslog -p daemon.err -t $(syslog_tag) -m \
1835 "check_pgs: The test database %s is not in the database catalog" \
1836 "${SCDB}"
1837 fi
1838
1839 rc_check_command=100
1840 else
1841 debug_message "Function: check_pgs - check if the database catalog is accessible with ${SCDB} was successful"
1842 fi
1843 fi
1844
1845 # manipulate the table SCTABLE and exit 100 if the inserted string is not there, exit 10 if the connection to
1846 # the database fails
1847
1848 if [ ${rc_check_command} -eq 0 ]
1849 then
1850
1851 debug_message "Function: check_pgs - manipulate the table ${SCTABLE}"
1852
1853 ${SU} ${USER} -c "${OPEN_BRACKET} ${TASK_COMMAND} ${LIBPATH} $HOST ${PASSWORD} ${ENV} ${DATA} ${ENV} ${PORT} ${PGROOT}/bin/psql -d ${SCDB} -U ${SCUSER} -c \"${DBTRUNC};${DBINS};${DBSEL}\" ${TBL_OUTPUT} ${CLOSE_BRACKET} ${TBL_ERRPUT} " >/dev/null
1854 rc_check_command=$?
1855
1856 # Return ${NOCONRET} if the connect fails, otherwise proceed with the check
1857
1858 if [ ${rc_check_command} -ne 0 ]
1859 then
1860
1861 debug_message "Function: check_pgs - connect to database ${SCDB} failed"
1862
1863 if [ ${wait_for_online} -eq 0 ]
1864 then
1865 cp /tmp/${RESOURCE}-${USER}-tbl-err ${LOGFILE}
1866 log_message err "check_pgs: rc<${NOCONRET}>"
1867 fi
1868
1869 rc_check_command=${NOCONRET}
1870
1871 else
1872
1873 # check if the test table could be manipulated successfully
1874
1875
1876 if ! ${GREP} "hello im there" /tmp/${RESOURCE}-${USER}-tbl-out >/dev/null 2>&1
1877 then
1878
1879 if [ ${wait_for_online} -eq 0 ]
1880 then
1881 # SCMSGS
1882 # @explanation
1883 # The monitoring action on the
1884 # specified table failed.
1885 # @user_action
1886 # None
1887 scds_syslog -p daemon.err -t $(syslog_tag) -m \
1888 "check_pgs: The test database manipulation failed for database %s, user %s and table %s" \
1889 "${SCDB}" "${SCUSER}" "${SCTABLE}"
1890 fi
1891
1892 rc_check_command=100
1893 debug_message "Function: check_pgs - manipulation of the table ${SCTABLE} failed"
1894
1895 else
1896
1897 debug_message "Function: check_pgs - manipulation of the table ${SCTABLE} successful"
1898
1899 fi
1900 fi
1901 fi
1902
1903 debug_message "Function: check_pgs - End"
1904 return ${rc_check_command}
1905 }
1906
1907 check_stdby()
1908 {
1909 #
1910 # Check if the current postgres database is configured or running as a standby database.
1911 # This function is called from the start command of the remote host.
1912 # The error messages are processed by scds_syslog, and they are transported via
1913 # standard out to the remote host.
1914 #
1915 # This function will generate up to two error messages in the postgres logfile.
1916
1917 debug_message "Function: check_stdby - Begin"
1918 ${SET_DEBUG}
1919
1920 rc_check_stdby_command=0
1921 if [ -f ${PGDATA}/recovery.conf ]
1922 then
1923
1924 # We are running as the PostgreSQL user, so exporting the environment is sufficient.
1925
1926 export PGPORT
1927
1928 # The variable PASSWORD is set to the database user login password.
1929
1930 if [ -n "${SCPASS}" ]
1931 then
1932 export PGPASSWORD=${SCPASS}
1933 fi
1934
1935 if [ -n "${PGHOST}" ]
1936 then
1937 export PGHOST
1938 fi
1939 export PGPORT
1940 export LD_LIBRARY_PATH
1941
1942 # check the database if it accepts inserts
1943
1944 ${PGROOT}/bin/psql -d ${SCDB} -U ${SCUSER} -c "insert into ${SCTABLE} (sccol) values('standby test');" >/dev/null 2>&1
1945 if [ ${?} -eq 0 ]
1946 then
1947 # SCMSGS
1948 # @explanation
1949 # The database is running as a primary database, but is configured to be a standby.
1950 # @user_action
1951 # If you want to start the old primary database, reload the primary and restart
1952 # the standby database.
1953 scds_syslog -p daemon.err -t $(syslog_tag) -m \
1954 "check_stdby: The database in %s is not running as a standby database, reload the primary and restart the standby database." \
1955 "${PGDATA}"
1956 rc_check_stdby_command=1
1957
1958 else
1959
1960 # Check if the rolchanger is currently doing his work.
1961
1962 if [ -f /tmp/${ROLECHG_RS}_rolechg.lck ]
1963 then
1964
1965 # SCMSGS
1966 # @explanation
1967 # The database is running as a standby database, but is currently reconfigured to run as a primary.
1968 # @user_action
1969 # If you want to start the old primary database, reload the primary and restart
1970 # the standby database.
1971 scds_syslog -p daemon.err -t $(syslog_tag) -m \
1972 "check_stdby: The database in %s is reconfigured to run as a primary database, reload the primary and restart the standby database." \
1973 "${PGDATA}"
1974 rc_check_stdby_command=1
1975 else
1976 debug_message "Function: check_stdby - the database in ${PGDATA} is configured or running as a standby database"
1977 fi
1978
1979 fi
1980
1981 else
1982
1983 # SCMSGS
1984 # @explanation
1985 # The database is not configured as a standby database.
1986 # @user_action
1987 # Create an appropriate recovery.conf command, reload the primary
1988 # and restart the standby database.
1989 scds_syslog -p daemon.err -t $(syslog_tag) -m \
1990 "check_stdby: The database in %s is not configured as a standby database, create the recovery.conf command" \
1991 "${PGDATA}"
1992 rc_check_stdby_command=1
1993
1994 fi
1995
1996 debug_message "Function: check_stdby - End"
1997 return ${rc_check_stdby_command}
1998 }