├── README.md ├── f5.automated_backup.LATEST.tmpl.tcl ├── f5.automated_backup.v3.0.0.tmpl.tcl ├── f5.automated_backup.v3.1.0.tmpl.tcl ├── f5.automated_backup.v3.1.1.tmpl ├── f5.automated_backup.v3.1.2.tmpl.tcl ├── f5.automated_backup.v3.1.3.tmpl.tcl ├── f5.automated_backup.v3.1.4.tmpl.tcl ├── f5.automated_backup.v3.1.5.tmpl.tcl ├── f5.automated_backup.v3.1.6.scripts.sh ├── f5.automated_backup.v3.1.6.tmpl.tcl ├── f5.automated_backup.v3.1.7.scripts.sh ├── f5.automated_backup.v3.1.7.tmpl.tcl ├── f5.automated_backup.v3.1.8.scripts.sh ├── f5.automated_backup.v3.1.8.tmpl.tcl ├── f5.automated_backup.v3.1.9.scripts.sh ├── f5.automated_backup.v3.1.9.tmpl.tcl ├── f5.automated_backup.v3.2.0.scripts.sh └── f5.automated_backup.v3.2.0.tmpl.tcl /README.md: -------------------------------------------------------------------------------- 1 | # f5-automated-backup-iapp 2 | F5 iApp for automated backups to the local device and to network locations. 3 | 4 | ## Intro 5 | Building on the significant work of Thomas Schockaert (and several other DevCentralites) I enhanced many aspects I needed for my own purposes, updated many things I noticed requested on the forums, and added additional documentation and clarification. As you may see in several of my comments on the original posts, I iterated through several 2.2.x versions and am now releasing v3.0.0. Below is the breakdown! 6 | 7 | Also, I have done quite a bit of testing (mostly on v13.1.0.1 lately) and I doubt I've caught everything, especially with all of the changes. Please post any questions or issues in the comments. 8 | 9 | Cheers! 10 | 11 | Daniel Tavernier (tabernarious) 12 | 13 | ## Related Posts 14 | * https://github.com/tabernarious/f5-automated-backup-iapp 15 | * https://devcentral.f5.com/s/articles/f5-iapp-automated-backup-1114 16 | * https://devcentral.f5.com/s/articles/f5-automated-backups-the-right-way 17 | * https://devcentral.f5.com/s/articles/complete-f5-automated-backup-solution 18 | * https://devcentral.f5.com/s/articles/complete-f5-automated-backup-solution-2-957 19 | * https://devcentral.f5.com/s/feed/0D51T00006i7Y72SAE 20 | 21 | ## Original v1.x.x and v2.x.x Features Kept (copied from an original post) 22 | * It allows you to choose between both UCS or SCF as backup-types. (whilst providing ample warnings about SCF not being a very good restore-option due to the incompleteness in some cases) 23 | * It allows you to provide a passphrase for the UCS archives (the standard GUI also does this, so the iApp should too) 24 | * It allows you to not include the private keys (same thing: standard GUI does it, so the iApp does it too) 25 | * It allows you to set a Backup Schedule for every X minutes/hours/days/weeks/months or a custom selection of days in the week 26 | * It allows you to set the exact time, minute of the hour, day of the week or day of the month when the backup should be performed (depending on the usefulness with regards to the schedule type) 27 | * It allows you to transfer the backup files to external devices using 4 different protocols, next to providing local storage on the device itself 28 | * SCP (username/private key without password) 29 | * SFTP (username/private key without password) 30 | * FTP (username/password) 31 | * SMB (now using TMOS v12.x.x compatible 'mount -t cifs', with username/password) 32 | * Local Storage (/var/local/ucs or /var/local/scf) 33 | * It stores all passwords and private keys in a secure fashion: encrypted by the master key of the unit (f5mku), rendering it safe to store the backups, including the credentials off-box 34 | * It has a configurable automatic pruning function for the Local Storage option, so the disk doesn't fill up (i.e. keep last X backup files) 35 | * It allows you to configure the filename using the date/time wildcards from the tcl [clock] command, as well as providing a variable to include the hostname 36 | * It requires only the WebGUI to establish the configuration you desire 37 | * It allows you to disable the processes for automated backup, without you having to remove the Application Service or losing any previously entered settings 38 | * For the external shellscripts it automatically generates, the credentials are stored in encrypted form (using the master key) 39 | * It allows you to no longer be required to make modifications on the linux command line to get your automated backups running after an RMA or restore operation 40 | * It cleans up after itself, which means there are no extraneous shellscripts or status files lingering around after the scripts execute 41 | 42 | ## New v3.0.0 Features 43 | * Supports multiple instances! (Deploy multiple copies of the iApp to save backups to different places or perhaps to keep daily backups locally and send weekly backups to a network drive.) 44 | * Fully ConfigSync compatible! (Encrypted values now in $script instead of local file.) 45 | * Long passwords supported! (Using "-A" with openssl which reads/writes base64 encoded strings as a single line.) 46 | * Added $script error checking for all remote backup types! (Using 'catch' to prevent tcl errors when $script aborts.) 47 | * Backup files are cleaned up after any $script errors due to new error checking. 48 | * Added logging! (Run logs sent to '/var/log/ltm' via logger command which is compatible with BIG-IP Remote Logging configuration (syslog). Run logs AND errors sent to '/var/tmp/scriptd.out'. Errors may include plain-text passwords which should not be in /var/log/ltm or syslog.) 49 | * Added custom cipher option for SCP! (In case BIG-IP and the destination server are not cipher-compatible out of the box.) 50 | * Added StrictHostKeyChecking=no option. (This is insecure and should only be used for testing--lots of warnings.) 51 | * Combined SCP and SFTP because they are both using SCP to perform the remote copy. (Easier to maintain!) 52 | -------------------------------------------------------------------------------- /f5.automated_backup.v3.0.0.tmpl.tcl: -------------------------------------------------------------------------------- 1 | #TMSH-VERSION: 13.1.0.1 2 | 3 | # iApp VERSIONS (From what I gathered perusing DevCentral) 4 | # ~v2.0 - 20140312 - Initially posted releases (v11.4.0-11.6.x? compatibility). (Developed/posted by Thomas Schockaert) 5 | # v2.1.1 - 20160916 - Retooled SMB upload from smbclient to "mount -t cifs" (v12.1+ compatibility). (Developed/posted by MAG) 6 | # v2.2.1 - 20171214 - Allowed multiple instances of iApp by leveraging $tmsh::app_name to create unique object names. (Developed by Daniel Tavernier/tabernarious) 7 | # v2.2.2 - 20171214 - Added "/" to "mount -t cifs" command and clarified/expanded help for SMB (CIFS) Destination Parameters. (Developed by Daniel Tavernier/tabernarious) 8 | # v2.2.3 - 20171214 - Set many fields to "required" and set reasonable default values to prevent loading/configuration errors. Expanded help regarding private keys. (Developed by Daniel Tavernier/tabernarious) 9 | # v2.2.4 - 20171214 - Added fix to force FTP to use binary upload. (Copied code posted by Roy van Dongen, posted by Daniel Tavernier/tabernarious) 10 | # v2.2.4a - 20171215 - Added items to FUTURE list. 11 | # v2.2.5 - 20171228 - Added notes about special characters in passwords. Added Deployment Information and ConfigSync sections. (Developed by Daniel Tavernier/tabernarious) 12 | # v2.2.5a - 20180117 - Added items to FUTURE list. 13 | # v2.2.5b4 - 20180118 - Moved encrypted values for SMB/CIFS to shell script which eliminates ConfigSync issues. Fixed long-password issue by using "-A" with openssl so that base64 encoded strings are written and read as a single line. (Developed by Daniel Tavernier/tabernarious) 14 | # v2.2.5b4+ - 20180118 - Refining changes to SMB/CIFS and replicating to other remote copy types. (Developed by Daniel Tavernier/tabernarious) 15 | # v3.0.0 - 20180124 - (Developed by Daniel Tavernier/tabernarious) 16 | # - Eliminated ConfigSync issues and removed ConfigSync notes section. (Encrypted values now in $script instead of local file.) 17 | # - Passwords now have no length limits. (Using "-A" with openssl which reads/writes base64 encoded strings as a single line.) 18 | # - Added $script error checking for all remote backup types. (Using 'catch' to prevent tcl errors when $script aborts.) 19 | # - Backup files are cleaned up after $script error due to new error checking. 20 | # - Added logging. (Run logs sent to '/var/log/ltm' via logger command which is compatible with BIG-IP Remote Logging configuration (syslog). Run logs AND errors sent to '/var/tmp/scriptd.out'. Errors may include plain-text passwords which should not be in /var/log/ltm or syslog.) 21 | # - Added custom cipher option for SCP. 22 | # - Added StrictHostKeyChecking=no option. 23 | # - Combined SCP and SFTP because they are both using SCP to perform the remote copy. 24 | 25 | # FUTURE 26 | # - Fix tcl warnings if possible. 27 | # - Escape special characters in password for SMB/CIFS (maybe others). 28 | 29 | #REFERENCES 30 | # F5 Automated Backups - The Right Way (https://devcentral.f5.com/articles/f5-automated-backups-the-right-way) 31 | # PASTEBIN f5.automated_backup_v2.0 (https://pastebin.com/YbDj3eMN) 32 | # Complete F5 Automated Backup Solution (https://devcentral.f5.com/codeshare/complete-f5-automated-backup-solution?lc=1) 33 | # Complete F5 Automated Backup Solution #2 (https://devcentral.f5.com/codeshare/complete-f5-automated-backup-solution-2-957) 34 | # Automated Backup Solution (https://devcentral.f5.com/questions/automated-backup-solution) 35 | # Generate Config Backup (https://devcentral.f5.com/codeshare?sid=285) 36 | # PASTEBIN f5.automated_backup_v2.2.5 (https://pastebin.com/TENAivwW) 37 | 38 | cli admin-partitions { 39 | update-partition Common 40 | } 41 | sys application template /Common/f5.automated_backup.v3.0.0 { 42 | actions { 43 | definition { 44 | html-help { 45 | } 46 | implementation { 47 | package require iapp 1.0.0 48 | iapp::template start 49 | 50 | tmsh::cd .. 51 | 52 | ## Backup type handler 53 | set backup_type $::backup_type__backup_type_select 54 | set create_backup_command_append_pass "" 55 | set create_backup_command_append_keys "" 56 | if { $backup_type eq "UCS (User Configuration Set)" } { 57 | set create_backup_command "tmsh::save /sys ucs" 58 | set backup_directory /var/local/ucs 59 | # Backup passphrase usage 60 | if { $::backup_type__backup_passphrase_select eq "Yes" } { 61 | set backup_passphrase $::backup_type__backup_passphrase 62 | set create_backup_command_append_pass "passphrase $backup_passphrase" 63 | } 64 | # Backup private key inclusion 65 | if { $::backup_type__backup_includeprivatekeys eq "No" } { 66 | set create_backup_command_append_keys "no-private-key" 67 | } 68 | set backup_file_name "" 69 | set backup_file_name_extension "" 70 | set backup_file_script_extension ".ucs" 71 | set scfextensionfix "" 72 | } 73 | elseif { $backup_type eq "SCF (Single Configuration File)" } { 74 | set create_backup_command "tmsh::save /sys config file" 75 | set backup_directory /var/local/scf 76 | set backup_file_name_extension ".scf" 77 | set backup_file_script_extension "" 78 | } 79 | 80 | if { $::destination_parameters__protocol_enable eq "Remotely via SCP/SFTP" } { 81 | # Get the F5 Master key 82 | set f5masterkey [exec f5mku -K] 83 | # Store the target server information securely, encrypted with the unit key 84 | set encryptedusername [exec echo "$::destination_parameters__scp_remote_username" | openssl aes-256-ecb -salt -a -A -k ${f5masterkey}] 85 | set encryptedserver [exec echo "$::destination_parameters__scp_remote_server" | openssl aes-256-ecb -salt -a -A -k ${f5masterkey}] 86 | set encrypteddirectory [exec echo "$::destination_parameters__scp_remote_directory" | openssl aes-256-ecb -salt -a -A -k ${f5masterkey}] 87 | # Clean the private key data before cleanup 88 | set cleaned_privatekey [exec echo "$::destination_parameters__scp_sshprivatekey" | sed -e "s/BEGIN RSA PRIVATE KEY/BEGIN;RSA;PRIVATE;KEY/g" -e "s/END RSA PRIVATE KEY/END;RSA;PRIVATE;KEY/g" -e "s/ /\\\n/g" -e "s/;/ /g"] 89 | # Encrypt the private key data before dumping to a file 90 | set encrypted_privatekey [exec echo "$cleaned_privatekey" | openssl aes-256-ecb -salt -a -A -k ${f5masterkey}] 91 | # Set optional cipher for SCP (e.g. aes256-gcm@openssh.com) 92 | if { "$::destination_parameters__scp_cipher" equals "" } { 93 | set scp_cipher "" 94 | } else { 95 | set scp_cipher "-c $::destination_parameters__scp_cipher" 96 | } 97 | # Set optional "StrictHostKeyChecking=no" 98 | if { "$::destination_parameters__scp_stricthostkeychecking" equals "Yes" } { 99 | set scp_stricthostkeychecking "-o StrictHostKeyChecking=yes" 100 | } else { 101 | set scp_stricthostkeychecking "-o StrictHostKeyChecking=no" 102 | } 103 | # Create the iCall action 104 | set script { 105 | exec echo "f5.automated_backup iApp TMSHAPPNAME: STARTED" >> /var/tmp/scriptd.out 106 | exec logger -p local0.info "f5.automated_backup iApp TMSHAPPNAME: STARTED" 107 | # Get the hostname of the device we're running on 108 | set host [tmsh::get_field_value [lindex [tmsh::get_config sys global-settings] 0] hostname] 109 | # Get the current date and time in a specific format 110 | set cdate [clock format [clock seconds] -format "FORMAT"] 111 | # Form the filename for the backup 112 | set fname "${cdate}BACKUPFILENAMEXTENSION" 113 | # Run the 'create backup' command 114 | exec echo "f5.automated_backup iApp TMSHAPPNAME: $fname GENERATING" >> /var/tmp/scriptd.out 115 | exec logger -p local0.info "f5.automated_backup iApp TMSHAPPNAME: $fname GENERATING" 116 | BACKUPCOMMAND $fname BACKUPAPPEND_PASS BACKUPAPPEND_KEYS 117 | exec echo "f5.automated_backup iApp TMSHAPPNAME: $fname SAVED LOCALLY" >> /var/tmp/scriptd.out 118 | exec logger -p local0.info "f5.automated_backup iApp TMSHAPPNAME: $fname SAVED LOCALLY" 119 | # Set the script filename 120 | set scriptfile "/var/tmp/f5.automated_backup__TMSHAPPNAME_scp.sh" 121 | # Clean, recreate, and run a custom bash script that will perform the SCP upload 122 | exec rm -f $scriptfile 123 | exec echo "yes" 124 | exec echo -e "scp_function()\n{\n\tf5masterkey=\$(f5mku -K)\n\tusername=\$(echo \"ENCRYPTEDUSERNAME\" | openssl aes-256-ecb -salt -a -A -d -k \${f5masterkey})\n\tserver=\$(echo \"ENCRYPTEDSERVER\" | openssl aes-256-ecb -salt -a -A -d -k \${f5masterkey})\n\tdirectory=\$(echo \"ENCRYPTEDDIRECTORY\" | openssl aes-256-ecb -salt -a -A -d -k \${f5masterkey})\n\techo \"ENCRYPTEDPRIVATEKEY\" | openssl aes-256-ecb -salt -a -A -d -k \${f5masterkey} > /var/tmp/TMSHAPPNAME_scp.key\n\n\tchmod 600 /var/tmp/TMSHAPPNAME_scp.key\n\tscp -i /var/tmp/TMSHAPPNAME_scp.key SCPCIPHER SCPSTRICTHOSTKEYCHECKING BACKUPDIRECTORY/${fname}BACKUPFILESCRIPTEXTENSION \${username}@\${server}:\${directory} 2>> /var/tmp/scriptd.out\n\tscp_result=\$?\n\trm -f /var/tmp/TMSHAPPNAME_scp.key\n\treturn \$scp_result\n}\n\nscp_function" > $scriptfile 125 | exec chmod +x $scriptfile 126 | exec echo "f5.automated_backup iApp TMSHAPPNAME: $fname REMOTE COPY (SCP) STARTING" >> /var/tmp/scriptd.out 127 | exec logger -p local0.info "f5.automated_backup iApp TMSHAPPNAME: $fname REMOTE COPY (SCP) STARTING" 128 | if { [catch {exec $scriptfile}] } { 129 | exec echo "f5.automated_backup iApp TMSHAPPNAME: $fname REMOTE COPY (SCP) FAILED (check for errors above)" >> /var/tmp/scriptd.out 130 | exec logger -p local0.crit "f5.automated_backup iApp TMSHAPPNAME: $fname REMOTE COPY (SCP) FAILED (see /var/tmp/scriptd.out for errors)" 131 | } else { 132 | exec echo "f5.automated_backup iApp TMSHAPPNAME: $fname REMOTE COPY (SCP) SUCCEEDED" >> /var/tmp/scriptd.out 133 | exec logger -p local0.notice "f5.automated_backup iApp TMSHAPPNAME: $fname REMOTE COPY (SCP) SUCCEEDED" 134 | } 135 | # Clean up local files 136 | exec rm -f $scriptfile 137 | exec rm -f /var/tmp/TMSHAPPNAME_scp.key 138 | exec rm -f BACKUPDIRECTORY/$fnameBACKUPFILESCRIPTEXTENSION 139 | exec echo "f5.automated_backup iApp TMSHAPPNAME: FINISHED" >> /var/tmp/scriptd.out 140 | exec logger -p local0.info "f5.automated_backup iApp TMSHAPPNAME: FINISHED" 141 | } 142 | set script [string map [list FORMAT [lindex [split $::destination_parameters__filename_format " "] 0]] $script] 143 | set script [string map [list BACKUPFILENAMEXTENSION $backup_file_name_extension BACKUPFILESCRIPTEXTENSION $backup_file_script_extension BACKUPDIRECTORY $backup_directory BACKUPCOMMAND $create_backup_command BACKUPAPPEND_PASS $create_backup_command_append_pass BACKUPAPPEND_KEYS $create_backup_command_append_keys TMSHAPPNAME $tmsh::app_name ENCRYPTEDUSERNAME $encryptedusername ENCRYPTEDSERVER $encryptedserver ENCRYPTEDDIRECTORY $encrypteddirectory ENCRYPTEDPRIVATEKEY $encrypted_privatekey SCPCIPHER $scp_cipher SCPSTRICTHOSTKEYCHECKING $scp_stricthostkeychecking] $script] 144 | } 145 | elseif { $::destination_parameters__protocol_enable eq "Remotely via SFTP--DEPRECATED)" } { 146 | # SFTP was originally implemented EXACTLY THE SAME as SCP. While refining the SCP implementation and adding detailed notes and documentation it no longer made sense to maintain these in parallel. 147 | # Set the config file 148 | set configfile "/config/f5.automated_backup__${tmsh::app_name}_sftp.conf" 149 | # Clean the configuration file for this protocol_enable 150 | exec rm -f $configfile 151 | # Get the F5 Master key 152 | set f5masterkey [exec f5mku -K] 153 | # Store the target server information securely, encrypted with the unit key 154 | exec echo "$::destination_parameters__sftp_remote_username" | openssl aes-256-ecb -salt -a -k ${f5masterkey} > $configfile 155 | exec echo "$::destination_parameters__sftp_remote_server" | openssl aes-256-ecb -salt -a -k ${f5masterkey} >> $configfile 156 | exec echo "$::destination_parameters__sftp_remote_directory" | openssl aes-256-ecb -salt -a -k ${f5masterkey} >> $configfile 157 | # Clean the private key data before cleanup 158 | set cleaned_privatekey [exec echo "$::destination_parameters__sftp_sshprivatekey" | sed -e "s/BEGIN RSA PRIVATE KEY/BEGIN;RSA;PRIVATE;KEY/g" -e "s/END RSA PRIVATE KEY/END;RSA;PRIVATE;KEY/g" -e "s/ /\\\n/g" -e "s/;/ /g"] 159 | # Encrypt the private key data before dumping to a file 160 | set encrypted_privatekey [exec echo "$cleaned_privatekey" | openssl aes-256-ecb -salt -a -k ${f5masterkey}] 161 | # Store the target server information securely, encrypted with the unit key 162 | exec echo "$encrypted_privatekey" >> $configfile 163 | # Create the iCall action 164 | set script { 165 | exec echo "f5.automated_backup iApp TMSHAPPNAME: STARTED" >> /var/tmp/scriptd.out 166 | exec logger -p local0.info "f5.automated_backup iApp TMSHAPPNAME: STARTED" 167 | # Get the hostname of the device we're running on 168 | set host [tmsh::get_field_value [lindex [tmsh::get_config sys global-settings] 0] hostname] 169 | # Get the current date and time in a specific format 170 | set cdate [clock format [clock seconds] -format "FORMAT"] 171 | # Form the filename for the backup 172 | set fname "${cdate}BACKUPFILENAMEXTENSION" 173 | # Run the 'create backup' command 174 | exec echo "f5.automated_backup iApp TMSHAPPNAME: $fname GENERATING" >> /var/tmp/scriptd.out 175 | exec logger -p local0.info "f5.automated_backup iApp TMSHAPPNAME: $fname GENERATING" 176 | BACKUPCOMMAND $fname BACKUPAPPEND_PASS BACKUPAPPEND_KEYS 177 | exec echo "f5.automated_backup iApp TMSHAPPNAME: $fname SAVED LOCALLY" >> /var/tmp/scriptd.out 178 | exec logger -p local0.info "f5.automated_backup iApp TMSHAPPNAME: $fname SAVED LOCALLY" 179 | # Set the config file 180 | set configfile "/config/f5.automated_backup__TMSHAPPNAME_sftp.conf" 181 | # Set the script filename 182 | set scriptfile "/var/tmp/f5.automated_backup__TMSHAPPNAME_sftp.sh" 183 | # Clean, recreate, run and reclean a custom bash script that will perform the SCP upload 184 | exec rm -f $scriptfile 185 | exec echo "yes" 186 | exec echo -e "put()\n{\n\tfields=\"username server directory\"\n\ti=1\n\tf5masterkey=\$(f5mku -K)\n\tfor current_field in \$fields ; do\n\t\tsedcommand=\"\${i}p\"\n\t\tcurrent_encrypted_value=\$(sed -n \"\$sedcommand\" $configfile)\n\t\tcurrent_decrypted_value=\$(echo \"\$current_encrypted_value\" | openssl aes-256-ecb -salt -a -d -k \$f5masterkey)\n\t\teval \"\$current_field=\$current_decrypted_value\"\n\t\tlet i=\$i+1\n\t\tunset current_encrypted_value current_decrypted_value sedcommand\n\tdone\n\tsed -n '4,\$p' $configfile | openssl aes-256-ecb -salt -a -d -k \$f5masterkey > /var/tmp/scp.key\n\tchmod 600 /var/tmp/scp.key\n\tscp -i /var/tmp/scp.key BACKUPDIRECTORY/$fnameBACKUPFILESCRIPTEXTENSION \${username}@\${server}:\${directory}\n\trm -f /var/tmp/scp.key\n\treturn \$?\n}\n\nput" > $scriptfile 187 | exec chmod +x $scriptfile 188 | exec echo "f5.automated_backup iApp TMSHAPPNAME: $fname REMOTE COPY (SFTP) STARTING" >> /var/tmp/scriptd.out 189 | exec logger -p local0.info "f5.automated_backup iApp TMSHAPPNAME: $fname REMOTE COPY (SFTP) STARTING" 190 | exec $scriptfile 191 | exec rm -f $scriptfile 192 | # Remove the backup file from the F5 193 | exec rm -f BACKUPDIRECTORY/$fnameBACKUPFILESCRIPTEXTENSION 194 | exec echo "f5.automated_backup iApp TMSHAPPNAME: FINISHED" >> /var/tmp/scriptd.out 195 | exec logger -p local0.info "f5.automated_backup iApp TMSHAPPNAME: FINISHED" 196 | } 197 | set script [string map [list FORMAT [lindex [split $::destination_parameters__filename_format " "] 0]] $script] 198 | set script [string map [list BACKUPFILENAMEXTENSION $backup_file_name_extension BACKUPFILESCRIPTEXTENSION $backup_file_script_extension BACKUPDIRECTORY $backup_directory BACKUPCOMMAND $create_backup_command BACKUPAPPEND_PASS $create_backup_command_append_pass BACKUPAPPEND_KEYS $create_backup_command_append_keys TMSHAPPNAME $tmsh::app_name] $script] 199 | } 200 | elseif { $::destination_parameters__protocol_enable eq "Remotely via FTP" } { 201 | # Get the F5 Master key 202 | set f5masterkey [exec f5mku -K] 203 | # Store the target server information securely, encrypted with the unit key 204 | set encryptedusername [exec echo "$::destination_parameters__ftp_remote_username" | openssl aes-256-ecb -salt -a -A -k ${f5masterkey}] 205 | set encryptedpassword [exec echo "$::destination_parameters__ftp_remote_password" | openssl aes-256-ecb -salt -a -A -k ${f5masterkey}] 206 | set encryptedserver [exec echo "$::destination_parameters__ftp_remote_server" | openssl aes-256-ecb -salt -a -A -k ${f5masterkey}] 207 | set encrypteddirectory [exec echo "$::destination_parameters__ftp_remote_directory" | openssl aes-256-ecb -salt -a -A -k ${f5masterkey}] 208 | # Create the iCall action 209 | set script { 210 | exec echo "f5.automated_backup iApp TMSHAPPNAME: STARTED" >> /var/tmp/scriptd.out 211 | exec logger -p local0.info "f5.automated_backup iApp TMSHAPPNAME: STARTED" 212 | # Get the hostname of the device we're running on 213 | set host [tmsh::get_field_value [lindex [tmsh::get_config sys global-settings] 0] hostname] 214 | # Get the current date and time in a specific format 215 | set cdate [clock format [clock seconds] -format "FORMAT"] 216 | # Form the filename for the backup 217 | set fname "${cdate}BACKUPFILENAMEXTENSION" 218 | # Run the 'create backup' command 219 | exec echo "f5.automated_backup iApp TMSHAPPNAME: $fname GENERATING" >> /var/tmp/scriptd.out 220 | exec logger -p local0.info "f5.automated_backup iApp TMSHAPPNAME: $fname GENERATING" 221 | BACKUPCOMMAND $fname BACKUPAPPEND_PASS BACKUPAPPEND_KEYS 222 | exec echo "f5.automated_backup iApp TMSHAPPNAME: $fname SAVED LOCALLY" >> /var/tmp/scriptd.out 223 | exec logger -p local0.info "f5.automated_backup iApp TMSHAPPNAME: $fname SAVED LOCALLY" 224 | # Set the config file 225 | set configfile "/config/f5.automated_backup__TMSHAPPNAME_ftp.conf" 226 | # Set the script filename 227 | set scriptfile "/var/tmp/f5.automated_backup__TMSHAPPNAME_ftp.sh" 228 | # Clean, recreate, run and reclean a custom bash script that will perform the FTP upload 229 | exec rm -f $scriptfile 230 | # Updated command v2.2.4 to force binary transfer. 231 | exec echo -e "ftp_function()\n{\n\tf5masterkey=\$(f5mku -K)\n\tusername=\$(echo \"ENCRYPTEDUSERNAME\" | openssl aes-256-ecb -salt -a -A -d -k \${f5masterkey})\n\tpassword=\$(echo \"ENCRYPTEDPASSWORD\" | openssl aes-256-ecb -salt -a -A -d -k \${f5masterkey})\n\tserver=\$(echo \"ENCRYPTEDSERVER\" | openssl aes-256-ecb -salt -a -A -d -k \${f5masterkey})\n\tdirectory=\$(echo \"ENCRYPTEDDIRECTORY\" | openssl aes-256-ecb -salt -a -A -d -k \${f5masterkey})\n\n\tftp_return=\$(ftp -n \${server} << END_FTP\nquote USER \${username}\nquote PASS \${password}\nbinary\nput BACKUPDIRECTORY/${fname}BACKUPFILESCRIPTEXTENSION \${directory}/${fname}BACKUPFILESCRIPTEXTENSION\nquit\nEND_FTP\n)\n\tif \[ \"\$ftp_return\" == \"\" \]\n\tthen\n\t\treturn 0\n\telse\n\t\techo \"\$ftp_return\" >> /var/tmp/scriptd.out\n\t\treturn 1\n\tfi\n}\n\nftp_function" > $scriptfile 232 | # Original command which allowed ascii transfer. 233 | #exec echo -e "put()\n{\n\tfields=\"username password server directory\"\n\ti=1\n\tf5masterkey=\$(f5mku -K)\n\tfor current_field in \$fields ; do\n\t\tsedcommand=\"\${i}p\"\n\t\tcurrent_encrypted_value=\$(sed -n \"\$sedcommand\" $configfile)\n\t\tcurrent_decrypted_value=\$(echo \"\$current_encrypted_value\" | openssl aes-256-ecb -salt -a -d -k \$f5masterkey)\n\t\teval \"\$current_field=\$current_decrypted_value\"\n\t\tlet i=\$i+1\n\t\tunset current_encrypted_value current_decrypted_value sedcommand\n\tdone\n\tftp -n \${server} << END_FTP\nquote USER \${username}\nquote PASS \${password}\nput BACKUPDIRECTORY/${fname}BACKUPFILESCRIPTEXTENSION \${directory}/${fname}BACKUPFILESCRIPTEXTENSION\nquit\nEND_FTP\n\treturn \$?\n}\n\nput" > $scriptfile 234 | exec chmod +x $scriptfile 235 | exec echo "f5.automated_backup iApp TMSHAPPNAME: $fname REMOTE COPY (FTP) STARTING" >> /var/tmp/scriptd.out 236 | exec logger -p local0.info "f5.automated_backup iApp TMSHAPPNAME: $fname REMOTE COPY (FTP) STARTING" 237 | if { [catch {exec $scriptfile}] } { 238 | exec echo "f5.automated_backup iApp TMSHAPPNAME: $fname REMOTE COPY (FTP) FAILED (check for errors above)" >> /var/tmp/scriptd.out 239 | exec logger -p local0.crit "f5.automated_backup iApp TMSHAPPNAME: $fname REMOTE COPY (FTP) FAILED (see /var/tmp/scriptd.out for errors)" 240 | } else { 241 | exec echo "f5.automated_backup iApp TMSHAPPNAME: $fname REMOTE COPY (FTP) SUCCEEDED" >> /var/tmp/scriptd.out 242 | exec logger -p local0.notice "f5.automated_backup iApp TMSHAPPNAME: $fname REMOTE COPY (FTP) SUCCEEDED" 243 | } 244 | # Clean up local files 245 | exec rm -f $scriptfile 246 | exec rm -f BACKUPDIRECTORY/$fnameBACKUPFILESCRIPTEXTENSION 247 | exec echo "f5.automated_backup iApp TMSHAPPNAME: FINISHED" >> /var/tmp/scriptd.out 248 | exec logger -p local0.info "f5.automated_backup iApp TMSHAPPNAME: FINISHED" 249 | } 250 | set script [string map [list FORMAT [lindex [split $::destination_parameters__filename_format " "] 0]] $script] 251 | set script [string map [list BACKUPFILENAMEXTENSION $backup_file_name_extension BACKUPFILESCRIPTEXTENSION $backup_file_script_extension BACKUPDIRECTORY $backup_directory BACKUPCOMMAND $create_backup_command BACKUPAPPEND_PASS $create_backup_command_append_pass BACKUPAPPEND_KEYS $create_backup_command_append_keys TMSHAPPNAME $tmsh::app_name ENCRYPTEDUSERNAME $encryptedusername ENCRYPTEDPASSWORD $encryptedpassword ENCRYPTEDSERVER $encryptedserver ENCRYPTEDDIRECTORY $encrypteddirectory] $script] 252 | } 253 | elseif { $::destination_parameters__protocol_enable eq "Remotely via SMB/CIFS" } { 254 | # Get the F5 Master key 255 | set f5masterkey [exec f5mku -K] 256 | # Store the target server information securely, encrypted with the unit key 257 | set encryptedusername [exec echo "$::destination_parameters__smb_remote_username" | openssl aes-256-ecb -salt -a -A -k ${f5masterkey}] 258 | set encryptedpassword [exec echo "$::destination_parameters__smb_remote_password" | openssl aes-256-ecb -salt -a -A -k ${f5masterkey}] 259 | set encryptedmsdomain [exec echo "$::destination_parameters__smb_remote_domain" | openssl aes-256-ecb -salt -a -A -k ${f5masterkey}] 260 | set encryptedserver [exec echo "$::destination_parameters__smb_remote_server" | openssl aes-256-ecb -salt -a -A -k ${f5masterkey}] 261 | set encryptedmsshare [exec echo "$::destination_parameters__smb_remote_path" | openssl aes-256-ecb -salt -a -A -k ${f5masterkey}] 262 | set encryptedmssubdir [exec echo "$::destination_parameters__smb_remote_directory" | openssl aes-256-ecb -salt -a -A -k ${f5masterkey}] 263 | set encryptedmountp [exec echo "$::destination_parameters__smb_local_mountdir" | openssl aes-256-ecb -salt -a -A -k ${f5masterkey}] 264 | # Create the iCall action 265 | set script { 266 | exec echo "f5.automated_backup iApp TMSHAPPNAME: STARTED" >> /var/tmp/scriptd.out 267 | exec logger -p local0.info "f5.automated_backup iApp TMSHAPPNAME: STARTED" 268 | # Get the hostname of the device we're running on 269 | set host [tmsh::get_field_value [lindex [tmsh::get_config sys global-settings] 0] hostname] 270 | # Get the current date and time in a specific format 271 | set cdate [clock format [clock seconds] -format "FORMAT"] 272 | # Form the filename for the backup 273 | set fname "${cdate}BACKUPFILENAMEXTENSION" 274 | # Run the 'create backup' command 275 | exec echo "f5.automated_backup iApp TMSHAPPNAME: $fname GENERATING" >> /var/tmp/scriptd.out 276 | exec logger -p local0.info "f5.automated_backup iApp TMSHAPPNAME: $fname GENERATING" 277 | BACKUPCOMMAND $fname BACKUPAPPEND_PASS BACKUPAPPEND_KEYS 278 | exec echo "f5.automated_backup iApp TMSHAPPNAME: $fname SAVED LOCALLY" >> /var/tmp/scriptd.out 279 | exec logger -p local0.info "f5.automated_backup iApp TMSHAPPNAME: $fname SAVED LOCALLY" 280 | # Set the script filename 281 | set scriptfile "/var/tmp/f5.automated_backup__TMSHAPPNAME_smb.sh" 282 | # Clean, recreate, run and reclean a custom bash script that will perform the SMB upload 283 | exec rm -f $scriptfile 284 | exec echo -e "\#\!/bin/sh\nf5masterkey=\$(f5mku -K)\nusername=\$(echo \"ENCRYPTEDUSERNAME\" | openssl aes-256-ecb -salt -a -A -d -k \${f5masterkey})\npassword=\$(echo \"ENCRYPTEDPASSWORD\" | openssl aes-256-ecb -salt -a -A -d -k \${f5masterkey})\nmsdomain=\$(echo \"ENCRYPTEDMSDOMAIN\" | openssl aes-256-ecb -salt -a -A -d -k \${f5masterkey})\nserver=\$(echo \"ENCRYPTEDSERVER\" | openssl aes-256-ecb -salt -a -A -d -k \${f5masterkey})\nmsshare=\$(echo \"ENCRYPTEDMSSHARE\" | openssl aes-256-ecb -salt -a -A -d -k \${f5masterkey})\nmssubdir=\$(echo \"ENCRYPTEDMSSUBDIR\" | openssl aes-256-ecb -salt -a -A -d -k \${f5masterkey})\nmountp=\$(echo \"ENCRYPTEDMOUNTP\" | openssl aes-256-ecb -salt -a -A -d -k \${f5masterkey})\ncd /var/local/ucs\nif \[ \! -d \${mountp} \]\nthen\n\tmkdir -p \${mountp}\n\tif \[ \$? -ne 0 \]\n\tthen\n\t\trm -f $fnameBACKUPFILESCRIPTEXTENSION\n\t\texit 1\n\tfi\nfi\nmount -t cifs //\${server}/\${msshare} \${mountp} -o user=\${username}%\${password},domain=\${msdomain} 2>> /var/tmp/scriptd.out\nif \[ \$? -ne 0 \]\n\tthen\n\trm -f $fnameBACKUPFILESCRIPTEXTENSION\n\texit 1\nfi\nfONSMB=\$(ls -t \${mountp}\${mssubdir}/\*.ucs 2>/dev/null| head -n 1 2>/dev/null)\nif \[ \"X\"\${fONSMB} \!= \"X\" \]\n\tthen\n\tsum1=\$(md5sum $fnameBACKUPFILESCRIPTEXTENSION | awk '{print \$1}')\n\tsum2=\$(md5sum \${fONSMB} | awk \'{print \$1}\')\n\tif \[ \${sum1} == \${sum2} \]\n\tthen\n\t\techo \"ERROR: File $fnameBACKUPFILESCRIPTEXTENSION already exists in //\${server}/\${msshare}/\${mssubdir}\" >> /var/tmp/scriptd.out\n\t\tumount \${mountp}\n\t\trm -f $fnameBACKUPFILESCRIPTEXTENSION\n\t\texit 1\n\tfi\nfi\ncp $fnameBACKUPFILESCRIPTEXTENSION \${mountp}\${mssubdir}\nrm -f $fnameBACKUPFILESCRIPTEXTENSION\numount \${mountp}\n\nexit 0\n\n" > $scriptfile 285 | exec chmod +x $scriptfile 286 | exec echo "f5.automated_backup iApp TMSHAPPNAME: $fname STARTING REMOTE COPY (SMB/CIFS)" >> /var/tmp/scriptd.out 287 | exec logger -p local0.info "f5.automated_backup iApp TMSHAPPNAME: $fname REMOTE COPY (SMB/CIFS) STARTING" 288 | if { [catch {exec $scriptfile}] } { 289 | exec echo "f5.automated_backup iApp TMSHAPPNAME: $fname REMOTE COPY (SMB/CIFS) FAILED (check for errors above)" >> /var/tmp/scriptd.out 290 | exec logger -p local0.crit "f5.automated_backup iApp TMSHAPPNAME: $fname REMOTE COPY (SMB/CIFS) FAILED (see /var/tmp/scriptd.out for errors)" 291 | } else { 292 | exec echo "f5.automated_backup iApp TMSHAPPNAME: $fname REMOTE COPY (SMB/CIFS) SUCCEEDED" >> /var/tmp/scriptd.out 293 | exec logger -p local0.notice "f5.automated_backup iApp TMSHAPPNAME: $fname REMOTE COPY (SMB/CIFS) SUCCEEDED" 294 | } 295 | # Clean up local files 296 | exec rm -f $scriptfile 297 | exec rm -f BACKUPDIRECTORY/$fnameBACKUPFILESCRIPTEXTENSION 298 | exec echo "f5.automated_backup iApp TMSHAPPNAME: FINISHED" >> /var/tmp/scriptd.out 299 | exec logger -p local0.info "f5.automated_backup iApp TMSHAPPNAME: FINISHED" 300 | } 301 | # Swap hostname/date format into archive filename based on iApp field 302 | set script [string map [list FORMAT [lindex [split $::destination_parameters__filename_format " "] 0]] $script] 303 | # Swap many variables into $script; due to the curly braces used to initially set $script, any referenced variables will *not* be expanded simply by deploying the iApp. 304 | set script [string map [list BACKUPFILENAMEXTENSION $backup_file_name_extension BACKUPFILESCRIPTEXTENSION $backup_file_script_extension BACKUPDIRECTORY $backup_directory BACKUPCOMMAND $create_backup_command BACKUPAPPEND_PASS $create_backup_command_append_pass BACKUPAPPEND_KEYS $create_backup_command_append_keys TMSHAPPNAME $tmsh::app_name ENCRYPTEDUSERNAME $encryptedusername ENCRYPTEDPASSWORD $encryptedpassword ENCRYPTEDMSDOMAIN $encryptedmsdomain ENCRYPTEDSERVER $encryptedserver ENCRYPTEDMSSHARE $encryptedmsshare ENCRYPTEDMSSUBDIR $encryptedmssubdir ENCRYPTEDMOUNTP $encryptedmountp] $script] 305 | } 306 | else { 307 | set script { 308 | exec echo "f5.automated_backup iApp TMSHAPPNAME: STARTED" >> /var/tmp/scriptd.out 309 | exec logger -p local0.info "f5.automated_backup iApp TMSHAPPNAME: STARTED" 310 | # Get the hostname of the device we're running on 311 | set host [tmsh::get_field_value [lindex [tmsh::get_config sys global-settings] 0] hostname] 312 | # Get the current date and time in a specific format 313 | set cdate [clock format [clock seconds] -format "FORMAT"] 314 | # Form the filename for the backup 315 | set fname "${cdate}BACKUPFILENAMEXTENSION" 316 | # Run the 'create backup' command 317 | exec echo "f5.automated_backup iApp TMSHAPPNAME: $fname GENERATING" >> /var/tmp/scriptd.out 318 | exec logger -p local0.info "f5.automated_backup iApp TMSHAPPNAME: $fname GENERATING" 319 | BACKUPCOMMAND $fname BACKUPAPPEND_PASS BACKUPAPPEND_KEYS 320 | exec echo "f5.automated_backup iApp TMSHAPPNAME: $fname SAVED LOCALLY" >> /var/tmp/scriptd.out 321 | exec logger -p local0.info "f5.automated_backup iApp TMSHAPPNAME: $fname SAVED LOCALLY" 322 | exec echo "f5.automated_backup iApp TMSHAPPNAME: FINISHED" >> /var/tmp/scriptd.out 323 | exec logger -p local0.info "f5.automated_backup iApp TMSHAPPNAME: FINISHED" 324 | } 325 | set script [string map [list FORMAT [lindex [split $::destination_parameters__filename_format " "] 0]] $script] 326 | set script [string map [list BACKUPFILENAMEXTENSION $backup_file_name_extension BACKUPFILESCRIPTEXTENSION $backup_file_script_extension BACKUPDIRECTORY $backup_directory BACKUPCOMMAND $create_backup_command BACKUPAPPEND_PASS $create_backup_command_append_pass BACKUPAPPEND_KEYS $create_backup_command_append_keys TMSHAPPNAME $tmsh::app_name] $script] 327 | } 328 | 329 | iapp::conf create sys icall script f5.automated_backup__${tmsh::app_name} definition \{ $script \} app-service none 330 | 331 | ## Get time info for setting first-occurrence on daily handler from iApp input 332 | set freq $::backup_schedule__frequency_select 333 | 334 | #Create the handlers 335 | if { $freq eq "Disable" } { 336 | 337 | } 338 | elseif { $freq eq "Every X Minutes" } { 339 | set everyxminutes $::backup_schedule__everyxminutes_value 340 | set interval [expr $everyxminutes*60] 341 | set cdate [clock format [clock seconds] -format "%Y-%m-%d:%H:%M"] 342 | iapp::conf create sys icall handler periodic f5.automated_backup__${tmsh::app_name}-handler \{ \ 343 | interval $interval \ 344 | first-occurrence $cdate:00 \ 345 | script f5.automated_backup__${tmsh::app_name} \} 346 | } 347 | elseif { $freq eq "Every X Hours" } { 348 | set everyxhours $::backup_schedule__everyxhours_value 349 | set interval [expr $everyxhours*3600] 350 | set minutes $::backup_schedule__everyxhours_min_select 351 | set cdate [clock format [clock seconds] -format "%Y-%m-%d:%H"] 352 | iapp::conf create sys icall handler periodic f5.automated_backup__${tmsh::app_name}-handler \{ \ 353 | interval $interval \ 354 | first-occurrence $cdate:$minutes:00 \ 355 | script f5.automated_backup__${tmsh::app_name} \} 356 | } 357 | elseif { $freq eq "Every X Days" } { 358 | set everyxdays $::backup_schedule__everyxdays_value 359 | set interval [expr $everyxdays*86400] 360 | set hours [lindex [split $::backup_schedule__everyxdays_time ":"] 0] 361 | set minutes [lindex [split $::backup_schedule__everyxdays_time ":"] 1] 362 | set cdate [clock format [clock seconds] -format "%Y-%m-%d"] 363 | iapp::conf create sys icall handler periodic f5.automated_backup__${tmsh::app_name}-handler \{ \ 364 | interval $interval \ 365 | first-occurrence $cdate:$hours:$minutes:00 \ 366 | script f5.automated_backup__${tmsh::app_name} \} 367 | } 368 | elseif { $freq eq "Every X Weeks" } { 369 | set everyxweeks $::backup_schedule__everyxweeks_value 370 | set interval [expr $everyxweeks*604800] 371 | set hours [lindex [split $::backup_schedule__everyxweeks_time ":"] 0] 372 | set minutes [lindex [split $::backup_schedule__everyxweeks_time ":"] 1] 373 | ## Get day of week info for setting first-occurence on weekly handler from iApp input 374 | array set dowmap { 375 | Sunday 0 376 | Monday 1 377 | Tuesday 2 378 | Wednesday 3 379 | Thursday 4 380 | Friday 5 381 | Saturday 6 382 | } 383 | set sday_name $::backup_schedule__everyxweeks_dow_select 384 | set sday_num $dowmap($sday_name) 385 | set cday_name [clock format [clock seconds] -format "%A"] 386 | set cday_num $dowmap($cday_name) 387 | set date_offset [expr 86400*($sday_num - $cday_num)] 388 | set date_final [clock format [expr [clock seconds] + $date_offset] -format "%Y-%m-%d"] 389 | iapp::conf create sys icall handler periodic f5.automated_backup__${tmsh::app_name}-handler \{ \ 390 | interval $interval \ 391 | first-occurrence $date_final:$hours:$minutes:00 \ 392 | script f5.automated_backup__${tmsh::app_name} \} 393 | } 394 | elseif { $freq eq "Every X Months" } { 395 | set everyxmonths $::backup_schedule__everyxmonths_value 396 | set interval [expr 60*60*24*365] 397 | set dom $::backup_schedule__everyxmonths_dom_select 398 | set hours [lindex [split $::backup_schedule__everyxmonths_time ":"] 0] 399 | set minutes [lindex [split $::backup_schedule__everyxmonths_time ":"] 1] 400 | for { set month 1 } { $month < 13 } { set month [expr $month+$everyxmonths] } { 401 | set cdate [clock format [clock seconds] -format "%Y-$month-$dom"] 402 | iapp::conf create sys icall handler periodic f5.automated_backup__${tmsh::app_name}-month_${month}-handler \{ \ 403 | interval $interval \ 404 | first-occurrence $cdate:$hours:$minutes:00 \ 405 | script f5.automated_backup__${tmsh::app_name} \} 406 | } 407 | } 408 | elseif { $freq eq "Custom" } { 409 | set hours [lindex [split $::backup_schedule__custom_time ":"] 0] 410 | set minutes [lindex [split $::backup_schedule__custom_time ":"] 1] 411 | ## Get day of week info for setting first-occurence on weekly handler from iApp input 412 | array set dowmap { 413 | Sunday 0 414 | Monday 1 415 | Tuesday 2 416 | Wednesday 3 417 | Thursday 4 418 | Friday 5 419 | Saturday 6 420 | } 421 | foreach sday_name $::backup_schedule__custom_dow_select { 422 | set sday_num $dowmap($sday_name) 423 | set cday_name [clock format [clock seconds] -format "%A"] 424 | set cday_num $dowmap($cday_name) 425 | set date_offset [expr 86400*($sday_num - $cday_num)] 426 | set date_final [clock format [expr [clock seconds] + $date_offset] -format "%Y-%m-%d"] 427 | iapp::conf create sys icall handler periodic f5.automated_backup__${tmsh::app_name}-handler-$sday_name \{ \ 428 | interval 604800 \ 429 | first-occurrence $date_final:$hours:$minutes:00 \ 430 | script f5.automated_backup__${tmsh::app_name} \} 431 | } 432 | } 433 | 434 | ## Automatic Pruning handler 435 | if { $::destination_parameters__protocol_enable eq "On this F5" } { 436 | set autoprune $::destination_parameters__pruning_enable 437 | if { $autoprune eq "Yes" } { 438 | set prune_conserve $::destination_parameters__keep_amount 439 | set today [clock format [clock seconds] -format "%Y-%m-%d"] 440 | set script { 441 | # Get the hostname of the device we're running on 442 | set host [tmsh::get_field_value [lindex [tmsh::get_config sys global-settings] 0] hostname] 443 | # Set the script filename 444 | set scriptfile "/var/tmp/autopruning.sh" 445 | # Clean, recreate, run and reclean a custom bash script that will perform the pruning 446 | exec rm -f $scriptfile 447 | exec echo -e "files_tokeep=\$(ls -t /var/local/ucs/*.ucs | head -n CONSERVE\)\nfor current_ucs_file in `ls /var/local/ucs/*.ucs` ; do\n\tcurrent_ucs_file_basename=`basename \$current_ucs_file`\n\tcheck_file=\$(echo \$files_tokeep | grep -w \$current_ucs_file_basename)\n\tif \[ \"\$check_file\" == \"\" \] ; then\n\t\trm -f \$current_ucs_file\n\tfi\ndone" > $scriptfile 448 | exec chmod +x $scriptfile 449 | exec $scriptfile 450 | exec rm -f $scriptfile 451 | } 452 | set script [string map [list CONSERVE $prune_conserve] $script] 453 | iapp::conf create sys icall script f5.automated_backup__${tmsh::app_name}_pruning definition \{ $script \} app-service none 454 | set cdate [clock format [clock seconds] -format "%Y-%m-%d:%H:%M"] 455 | # Interval can be increased as needed if pruning every minute is problematic 456 | iapp::conf create sys icall handler periodic f5.automated_backup__${tmsh::app_name}_pruning-handler \{ \ 457 | interval 60 \ 458 | first-occurrence $cdate:00 \ 459 | script f5.automated_backup__${tmsh::app_name}_pruning \} 460 | } 461 | } 462 | iapp::template end 463 | } 464 | macro { 465 | } 466 | presentation { 467 | section deployment_info { 468 | message deployment_info_first_time "Deploying the iApp may not trigger an immediate backup." 469 | message deployment_info_updates "To force the iApp to run a backup it is easiest to set the Backup Schedule to 'Every X Days', 'X equals 1', with a time earlier than right now (e.g. 01:00). This will set the first-occurrence parameter for the iCall handler to today at 01:00 which will trigger immediately (assuming the BIG-IP thinks it is after 1am). Redeploying the iApp will not trigger immediate backups unless the iCall handler is recreated which only happens if a change is made to the Backup Schedule. Simply change the time to 01:01 and redeploy with new settings to force an immediate backup attempt. When testing is complete, set the Backup Schedule to the desired ongoing schedule." 470 | message deployment_info_logs "The general log for all iApps is '/var/tmp/scriptd.out'. This iApp adds run logs and errors to '/var/tmp/scriptd.out'. Additionally, this iApp sends run logs (not full error messages) to '/var/log/ltm' (compatible with BIG-IP Remote Logging configuration)." 471 | } 472 | section backup_type { 473 | choice backup_type_select display "xlarge" { "UCS (User Configuration Set)", "SCF (Single Configuration File)" } 474 | optional ( backup_type_select == "SCF (Single Configuration File)" ) { 475 | message backup_help_scf "WARNING: Beware of choosing SCF file as not all configuration is included therein. Please check out SOL13408 (http://support.f5.com/kb/en-us/solutions/public/13000/400/sol13408.html) for more information." 476 | } 477 | optional ( backup_type_select == "UCS (User Configuration Set)" ) { 478 | choice backup_passphrase_select display "small" { "Yes", "No" } 479 | optional ( backup_passphrase_select == "Yes" ) { 480 | message backup_help_passphrase "WARNING: Losing the passphase will render the archives unusable. The encrypted UCS archive will be a PGP encoded file, *not* simply a tar.gz with a password on it." 481 | password backup_passphrase required display "large" 482 | } 483 | choice backup_includeprivatekeys display "small" { "Yes", "No" } 484 | optional ( backup_includeprivatekeys == "No" ) { 485 | message backup_help_privatekeys "WARNING: A UCS archive that does not contain the private keys CANNOT be used for restoring the device. It should be used for transfers to external services to whom you do not wish to disclose the private keys." 486 | } 487 | } 488 | } 489 | section backup_schedule { 490 | choice frequency_select display "large" { "Disable", "Every X Minutes", "Every X Hours", "Every X Days", "Every X Weeks", "Every X Months", "Custom" } 491 | optional ( frequency_select == "Every X Minutes" ) { 492 | editchoice everyxminutes_value default "30" display "small" { "1", "2", "5", "10", "15", "20", "30", "45", "60" } 493 | } 494 | optional ( frequency_select == "Every X Hours" ) { 495 | editchoice everyxhours_value default "1" display "small" { "1", "2", "3", "4", "6", "12", "24" } 496 | choice everyxhours_min_select display "small" tcl { 497 | for { set x 0 } { $x < 60 } { incr x } { 498 | append mins "$x\n" 499 | } 500 | return $mins 501 | } 502 | } 503 | optional ( frequency_select == "Every X Days" ) { 504 | editchoice everyxdays_value default "1" display "small" { "1", "2", "3", "4", "5", "7", "14" } 505 | string everyxdays_time required display "medium" 506 | } 507 | optional ( frequency_select == "Every X Weeks" ) { 508 | editchoice everyxweeks_value default "1" display "small" { "1", "2", "3", "4", "5", "7", "14" } 509 | choice everyxweeks_dow_select default "Sunday" display "medium" { "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday" } 510 | string everyxweeks_time required display "small" 511 | } 512 | optional ( frequency_select == "Every X Months" ) { 513 | editchoice everyxmonths_value default "1" display "small" { "1", "2", "3", "6", "12" } 514 | choice everyxmonths_dom_select display "small" tcl { 515 | for { set x 1 } { $x < 31 } { incr x } { 516 | append days "$x\n" 517 | } 518 | return $days 519 | } 520 | string everyxmonths_time required display "small" 521 | } 522 | optional ( frequency_select == "Custom" ) { 523 | multichoice custom_dow_select default {"Sunday"} display "medium" { "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday" } 524 | string custom_time required display "small" 525 | } 526 | } 527 | optional ( backup_schedule.frequency_select != "Disable" ) { 528 | section destination_parameters { 529 | choice protocol_enable display "xlarge" { "On this F5", "Remotely via SCP/SFTP", "Remotely via SMB/CIFS", "Remotely via FTP" } 530 | optional ( protocol_enable == "Remotely via SCP/SFTP") { 531 | message scp_sftp_help "A connection to an SSH server can be establish using both SCP and SFTP. SCP is more efficient for copying files to a remote network destination while, for interactive sessions, the SFTP protocol offers more features. This iApp uses SCP." 532 | string scp_remote_server required display "medium" validator "IpAddress" 533 | message scp_remote_server_help "IMPORTANT: Check '/root/.ssh/known_hosts' on each BIG-IP (including HA peers) to ensure the Destination IP above is listed. On each BIG-IP that does not list the Destination IP, connect directly to the Destination IP using the scp or ssh command. You will be asked to verify the 'RSA key fingerprint'. Entering 'yes' will store the fingerprint in '/root/.ssh/known_hosts' and allow subsequent connections without further verification. If IP from the CLI on all BIG-IPs (including HA peers) and verify/accept the fingerprint which should add an entry to the known_hosts file." 534 | choice scp_stricthostkeychecking default "Yes" display "large" { "Yes", "No (INSECURE)" } 535 | optional ( scp_stricthostkeychecking == "No (INSECURE)" ) { 536 | message scp_stricthostkeychecking_warning1 "WARNING: Selecting 'No (INSECURE)' will ignore certificate verification for connections this iApp makes to the server configured above. Backups could be copied to an unintended server, including one owned by a bad actor." 537 | } 538 | message scp_stricthostkeychecking_help1 "It is MOST SECURE to select Yes, which is the SCP/SSH default setting and which will not allow connections to unknown servers. A server is considered 'unknown' until an SSH key fingerprint has been verified, or if the destination SSL certificate changes and the fingerprint no longer matches." 539 | optional ( scp_stricthostkeychecking == "Yes" ) { 540 | message scp_stricthostkeychecking_help2 "Selecting 'No (INSECURE)' will ignore certificate verification for connections this iApp makes to the server configured above." 541 | message scp_stricthostkeychecking_trouble1 "TROUBLESHOOTING: If the SCP script fails with a 'Host key verification failed' or 'No RSA host key is known for' error (which can viewed in /var/tmp/scriptd.out after deploying this iApp), review the IMPORTANT steps (under Destination IP) above regarding the known_hosts file to resolve the issue. Also, review additional troubleshooting notes." 542 | message scp_stricthostkeychecking_trouble2 "TROUBLESHOOTING: If the SCP script fails with a 'WARNING: REMOTE HOST IDENTIFICATION HAS CHANGED!' error (which can viewed in /var/tmp/scriptd.out after deploying this iApp), the certificate on the destination server has changed. This could mean 1) The certificate was updated legitimately, or 2) There is an IP conflict and the script is connecting to the wrong server, or 3) the destination server was replaced or rebuilt and has a new certificate, or 4) a bad actor is intercepting the connection (man-in-the-middle) and the script is rightly warning you to not connect. Investigate the destination server before proceeding." 543 | } 544 | string scp_remote_username required display "medium" 545 | password scp_sshprivatekey required display "large" 546 | message scp_encrypted_field_storage_help "Private key must be non-encrypted and in 'OpenSSH' base64 format. As an example run 'ssh-keygen -t -b 2048 -o -a 100' from the CLI, step through the questions, and view the resulting private key (by default ssh-keygen will save the key to ~/.ssh/id_rsa)." 547 | message scp_encrypted_field_storage_help2 "Passwords and private keys are stored in an encrypted format. The salt for the encryption algorithm is the F5 cluster's Master Key. The master key is not shared when exporting a qkview or UCS, thus rendering your passwords and private keys safe if a backup file were to be stored off-box." 548 | editchoice scp_cipher display "xlarge" { "aes128-ctr", "aes192-ctr", "aes256-ctr", "aes128-gcm@openssh.com", "chacha20-poly1305@openssh.com" } 549 | message scp_cipher_help "Depending on the version of F5 TMOS and the ssh configuration of the destination server, there may be no matching ciphers resulting in a 'no matching cipher found' error (which can viewed in /var/tmp/scriptd.out after deploying this iApp or it can be tested/demonstrated by attempting an scp or ssh connection from this device to the destination server). Find the word 'server' in the error and note the ciphers listed; select one of these ciphers from the list above or paste in one not listed." 550 | string scp_remote_directory display "medium" 551 | } 552 | optional ( protocol_enable == "Remotely via SFTP--DEPRECATED") { 553 | string sftp_remote_server required display "medium" validator "IpAddress" 554 | string sftp_remote_username required display "medium" 555 | password sftp_sshprivatekey required display "large" 556 | message sftp_encrypted_field_storage_help "Private key must be in 'OpenSSH' base64 format. As an example run 'ssh-keygen -t -b 2048 -o -a 100' from the CLI, step through the questions, and view the resulting private key (default location is ~/.ssh/id_rsa after)." 557 | message sftp_encrypted_field_storage_help2 "Passwords and private keys are stored in an encrypted format. The salt for the encryption algorithm is the F5 cluster's Master Key. The master key is not shared when exporting a qkview or UCS, thus rendering your passwords and private keys safe if a backup file were to be stored off-box." 558 | string sftp_remote_directory display "medium" 559 | } 560 | optional ( protocol_enable == "Remotely via SMB/CIFS") { 561 | string smb_remote_server required display "medium" validator "IpAddress" 562 | message smb_remote_server_help "Ensure this Destination IP is reachable on port 139." 563 | string smb_remote_domain required display "medium" 564 | string smb_remote_username required display "medium" 565 | password smb_remote_password display "medium" 566 | message smb_remote_password_help "Special characters within passwords must be escaped (add a backslash before each special character as you input the password)." 567 | message smb_remote_password_help2 "Passwords and private keys are stored in an encrypted format. The salt for the encryption algorithm is the F5 cluster's Master Key. The master key is not shared when exporting a qkview or UCS, thus rendering your passwords and private keys safe if a backup file were to be stored off-box." 568 | string smb_remote_path required display "medium" 569 | message smb_remote_path_help "SMB share on a remote server. Do not include leading and trailing slashes. If the full share path is //SERVER/SHARE, enter SHARE in this field. If the full share path is //SERVER/PATH/SHARE, enter PATH/SHARE in this field." 570 | string smb_remote_directory display "medium" 571 | message smb_remote_directory_help "Relative path inside the SMB share to copy the file. Leave this field empty to store in root of SMB share. Include one leading slash and no trailing slashes. If the target directory is //SERVER/SHARE/PATH/DIRECTORY, enter /PATH/DIRECTORY in this field." 572 | string smb_local_mountdir required default "/var/tmp/cifs" display "medium" 573 | message smb_local_mountdir_help "Read-Write path on local F5 where SMB share will be mounted. Include one leading slash and no trailing slashes, for example /var/tmp/cifs" 574 | } 575 | optional ( protocol_enable == "Remotely via FTP") { 576 | string ftp_remote_server required display "medium" validator "IpAddress" 577 | string ftp_remote_username required display "medium" 578 | password ftp_remote_password display "medium" 579 | message ftp_encrypted_field_storage_help "Passwords and private keys are stored in an encrypted format. The salt for the encryption algorithm is the F5 cluster's Master Key. The master key is not shared when exporting a qkview or UCS, thus rendering your passwords and private keys safe if a backup file were to be stored off-box." 580 | string ftp_remote_directory display "medium" 581 | } 582 | editchoice filename_format display "xxlarge" tcl { 583 | set host [tmsh::get_field_value [lindex [tmsh::get_config sys global-settings] 0] hostname] 584 | set formats "" 585 | append formats {%Y%m%d%H%M%S_${host} => } 586 | append formats [clock format [clock seconds] -format "%Y%m%d%H%M%S_${host}"] 587 | append formats "\n" 588 | append formats {%Y%m%d_%H%M%S_${host} => } 589 | append formats [clock format [clock seconds] -format "%Y%m%d_%H%M%S_${host}"] 590 | append formats "\n" 591 | append formats {%Y%m%d_${host} => } 592 | append formats [clock format [clock seconds] -format "%Y%m%d_${host}"] 593 | append formats "\n" 594 | append formats {${host}_%Y%m%d%H%M%S => } 595 | append formats [clock format [clock seconds] -format "${host}_%Y%m%d%H%M%S"] 596 | append formats "\n" 597 | append formats {${host}_%Y%m%d_%H%M%S => } 598 | append formats [clock format [clock seconds] -format "${host}_%Y%m%d_%H%M%S"] 599 | append formats "\n" 600 | append formats {${host}_%Y%m%d => } 601 | append formats [clock format [clock seconds] -format "${host}_%Y%m%d"] 602 | append formats "\n" 603 | return $formats 604 | } 605 | message filename_format_help "You can select one, or create your own with all the [clock format] wildcards available in the tcl language, plus ${host} for the hostname. (http://www.tcl.tk/man/tcl8.6/TclCmd/clock.htm)" 606 | optional ( protocol_enable == "On this F5" ) { 607 | choice pruning_enable display "small" { "No", "Yes" } 608 | optional ( pruning_enable == "Yes" ) { 609 | editchoice keep_amount display "small" { "1", "2", "3", "4", "5", "6", "7", "8", "9", "10" } 610 | message pruning_help "Warning: if you decide to manually create a backupfile in the default directory, the automatic pruning will clean it if it doesn't match the 'newest X files' in that directory." 611 | } 612 | } 613 | } 614 | } 615 | text { 616 | deployment_info "Deployment Information" 617 | deployment_info.deployment_info_first_time "First Time Deployment:" 618 | deployment_info.deployment_info_updates "Testing the iApp:" 619 | deployment_info.deployment_info_logs "Logging:" 620 | backup_type "Backup Type" 621 | backup_type.backup_type_select "Select the type of backup:" 622 | backup_type.backup_passphrase_select "Use a passphrase to encrypt the UCS archive:" 623 | backup_type.backup_passphrase "What is the passphrase you want to use?" 624 | backup_type.backup_includeprivatekeys "Include the private keys in the archives?" 625 | backup_type.backup_help_scf "" 626 | backup_type.backup_help_passphrase "" 627 | backup_type.backup_help_privatekeys "" 628 | backup_schedule "Backup Schedule" 629 | backup_schedule.frequency_select "Frequency:" 630 | backup_schedule.everyxminutes_value "Where X equals:" 631 | backup_schedule.everyxhours_value "Where X equals:" 632 | backup_schedule.everyxhours_min_select "At what minute of each X hours should the backup occur?" 633 | backup_schedule.everyxdays_value "Where X equals:" 634 | backup_schedule.everyxdays_time "At what time on each X days should the backup occur? (Ex.: 15:25)" 635 | backup_schedule.everyxweeks_value "Where X equals:" 636 | backup_schedule.everyxweeks_time "At what time on the chosen day of each X weeks should the backup occur? (e.g. 04:15, 21:30)" 637 | backup_schedule.everyxweeks_dow_select "On what day of each X weeks should the backup should occur:" 638 | backup_schedule.everyxmonths_value "Where X equals:" 639 | backup_schedule.everyxmonths_time "At what time on the chosen day of each X months should the backup occur? (e.g. 04:15, 21:30)" 640 | backup_schedule.everyxmonths_dom_select "On what day of each X months should the backup should occur:" 641 | backup_schedule.custom_time "At what time on each selected day should the backup occur? (e.g. 04:15, 21:30)" 642 | backup_schedule.custom_dow_select "Choose the days of the week the backup should occur:" 643 | destination_parameters "Destination Parameters" 644 | destination_parameters.protocol_enable "Where do the backup files need to be saved?" 645 | destination_parameters.scp_sftp_help "SCP or SFTP?" 646 | destination_parameters.scp_remote_server "Destination IP:" 647 | destination_parameters.scp_remote_server_help "" 648 | destination_parameters.scp_stricthostkeychecking "StrictHostKeyChecking" 649 | destination_parameters.scp_stricthostkeychecking_help1 "" 650 | destination_parameters.scp_stricthostkeychecking_help2 "" 651 | destination_parameters.scp_stricthostkeychecking_trouble1 "" 652 | destination_parameters.scp_stricthostkeychecking_trouble2 "" 653 | destination_parameters.scp_stricthostkeychecking_warning1 "" 654 | destination_parameters.scp_remote_username "Username:" 655 | destination_parameters.scp_sshprivatekey "Copy/Paste the SSH private key to be used for passwordless authentication:" 656 | destination_parameters.scp_encrypted_field_storage_help "" 657 | destination_parameters.scp_encrypted_field_storage_help2 "" 658 | destination_parameters.scp_remote_directory "Remote directory for archive upload:" 659 | destination_parameters.scp_cipher "Cipher" 660 | destination_parameters.scp_cipher_help "" 661 | destination_parameters.sftp_remote_server "Destination IP:" 662 | destination_parameters.sftp_remote_username "Username:" 663 | destination_parameters.sftp_sshprivatekey "Copy/Paste the non-encrypted SSH private key to be used for passwordless authentication:" 664 | destination_parameters.sftp_encrypted_field_storage_help "" 665 | destination_parameters.sftp_encrypted_field_storage_help2 "" 666 | destination_parameters.sftp_remote_directory "Remote directory for archive upload:" 667 | destination_parameters.smb_remote_server "Destination IP:" 668 | destination_parameters.smb_remote_server_help "" 669 | destination_parameters.smb_remote_username "Username:" 670 | destination_parameters.smb_remote_domain "Domain or Hostname:" 671 | destination_parameters.smb_remote_password "Password:" 672 | destination_parameters.smb_remote_password_help "" 673 | destination_parameters.smb_remote_password_help2 "" 674 | destination_parameters.smb_remote_path "SMB/CIFS share name:" 675 | destination_parameters.smb_remote_path_help "" 676 | destination_parameters.smb_remote_directory "Target path inside SMB Share:" 677 | destination_parameters.smb_remote_directory_help "" 678 | destination_parameters.smb_local_mountdir "Local mount point:" 679 | destination_parameters.smb_local_mountdir_help "" 680 | destination_parameters.ftp_remote_username "Username:" 681 | destination_parameters.ftp_remote_password "Password:" 682 | destination_parameters.ftp_encrypted_field_storage_help "" 683 | destination_parameters.ftp_remote_server "Destination IP:" 684 | destination_parameters.ftp_remote_directory "Set the remote directory the archive should be copied to:" 685 | destination_parameters.filename_format "Select the filename format:" 686 | destination_parameters.filename_format_help "" 687 | destination_parameters.pruning_enable "Activate automatic pruning?" 688 | destination_parameters.pruning_help "" 689 | destination_parameters.keep_amount "Amount of files to keep at any given time:" 690 | } 691 | } 692 | role-acl { admin manager resource-admin } 693 | run-as none 694 | } 695 | } 696 | description none 697 | ignore-verification false 698 | requires-bigip-version-max none 699 | requires-bigip-version-min 12.1.0 700 | requires-modules { ltm } 701 | signing-key none 702 | tmpl-checksum none 703 | tmpl-signature none 704 | } -------------------------------------------------------------------------------- /f5.automated_backup.v3.1.0.tmpl.tcl: -------------------------------------------------------------------------------- 1 | # iApp VERSIONS (From what I gathered perusing DevCentral) 2 | # ~v2.0 - 20140312 - Initially posted releases (v11.4.0-11.6.x? compatibility). (Developed/posted by Thomas Schockaert) 3 | # v2.1.1 - 20160916 - Retooled SMB upload from smbclient to "mount -t cifs" (v12.1+ compatibility). (Developed/posted by MAG) 4 | # v2.2.1 - 20171214 - Allowed multiple instances of iApp by leveraging $tmsh::app_name to create unique object names. (Developed by Daniel Tavernier/tabernarious) 5 | # v2.2.2 - 20171214 - Added "/" to "mount -t cifs" command and clarified/expanded help for SMB (CIFS) Destination Parameters. (Developed by Daniel Tavernier/tabernarious) 6 | # v2.2.3 - 20171214 - Set many fields to "required" and set reasonable default values to prevent loading/configuration errors. Expanded help regarding private keys. (Developed by Daniel Tavernier/tabernarious) 7 | # v2.2.4 - 20171214 - Added fix to force FTP to use binary upload. (Copied code posted by Roy van Dongen, posted by Daniel Tavernier/tabernarious) 8 | # v2.2.4a - 20171215 - Added items to FUTURE list. 9 | # v2.2.5 - 20171228 - Added notes about special characters in passwords. Added Deployment Information and ConfigSync sections. (Developed by Daniel Tavernier/tabernarious) 10 | # v2.2.5a - 20180117 - Added items to FUTURE list. 11 | # v2.2.5b4 - 20180118 - Moved encrypted values for SMB/CIFS to shell script which eliminates ConfigSync issues. Fixed long-password issue by using "-A" with openssl so that base64 encoded strings are written and read as a single line. (Developed by Daniel Tavernier/tabernarious) 12 | # v2.2.5b4+ - 20180118 - Refining changes to SMB/CIFS and replicating to other remote copy types. (Developed by Daniel Tavernier/tabernarious) 13 | # v3.0.0 - 20180124 - (Developed by Daniel Tavernier/tabernarious) 14 | # - Eliminated ConfigSync issues and removed ConfigSync notes section. (Encrypted values now in $script instead of local file.) 15 | # - Passwords now have no length limits. (Using "-A" with openssl which reads/writes base64 encoded strings as a single line.) 16 | # - Added $script error checking for all remote backup types. (Using 'catch' to prevent tcl errors when $script aborts.) 17 | # - Backup files are cleaned up after $script error due to new error checking. 18 | # - Added logging. (Run logs sent to '/var/log/ltm' via logger command which is compatible with BIG-IP Remote Logging configuration (syslog). Run logs AND errors sent to '/var/tmp/scriptd.out'. Errors may include plain-text passwords which should not be in /var/log/ltm or syslog.) 19 | # - Added custom cipher option for SCP. 20 | # - Added StrictHostKeyChecking=no option. 21 | # - Combined SCP and SFTP because they are both using SCP to perform the remote copy. 22 | # v3.1.0 - 20180201 - (Developed by Daniel Tavernier/tabernarious) 23 | # - Removed "app-service none" from iCall objects. The iCall objects are now created as part of the Application Service (iApp) and are properly cleaned up if the iApp is redeployed or deleted. 24 | # - Reasonably tested on 11.5.4 HF2 (SMB worked fine using "mount -t cifs") and altered requires-bigip-version-min to match. 25 | # - Fixing error regarding "script did not successfully complete: (can't read "::destination_parameters__protocol_enable": no such variable" by encompassing most of the "implementation" in a block that first checks $::backup_schedule__frequency_select for "Disable". 26 | # - Added default value to "filename format". 27 | # - Changed UCS default value for $backup_file_name_extension to ".ucs" and added $fname_noext. 28 | # - Removed old SFTP sections and references (now handled through SCP/SFTP). 29 | # - Adjusted logging: added "sleep 1" to ensure proper logging; added $backup_directory to log message. 30 | # - Adjusted some help messages. 31 | 32 | # KNOWN ISSUES 33 | # - Some tcl warnings when loading configuration. 34 | # - Passwords with special characters may cause tcl or bash errors; a backslash must be entered by the user in front of each special character for proper escaping. 35 | # - F5 TMOS 11.4.1 - 11.5.3 untested and may work. 36 | # - BACKUPFILESCRIPTEXTENSION is not understood and may not be needed. 37 | # - Automatic pruning is not 38 | 39 | #REFERENCES 40 | # Git Repository for f5-automated-backup-iapp ( https://github.com/tabernarious/f5-automated-backup-iapp ) 41 | # F5 iApp Automated Backup ( https://devcentral.f5.com/codeshare/f5-iapp-automated-backup-1114 ) 42 | # F5 Automated Backups - The Right Way ( https://devcentral.f5.com/articles/f5-automated-backups-the-right-way ) 43 | # PASTEBIN f5.automated_backup_v2.0 ( https://pastebin.com/YbDj3eMN ) 44 | # Complete F5 Automated Backup Solution ( https://devcentral.f5.com/codeshare/complete-f5-automated-backup-solution?lc=1 ) 45 | # Complete F5 Automated Backup Solution #2 ( https://devcentral.f5.com/codeshare/complete-f5-automated-backup-solution-2-957 ) 46 | # Automated Backup Solution ( https://devcentral.f5.com/questions/automated-backup-solution ) 47 | # Generate Config Backup ( https://devcentral.f5.com/codeshare?sid=285 ) 48 | # PASTEBIN f5.automated_backup_v3.0.0 ( https://pastebin.com/TENAivwW ) 49 | 50 | cli admin-partitions { 51 | update-partition Common 52 | } 53 | sys application template /Common/f5.automated_backup.v3.1.0 { 54 | actions { 55 | definition { 56 | html-help { 57 | } 58 | implementation { 59 | package require iapp 1.0.0 60 | iapp::template start 61 | 62 | tmsh::cd .. 63 | 64 | ## Backup type handler 65 | set backup_type $::backup_type__backup_type_select 66 | set create_backup_command_append_pass "" 67 | set create_backup_command_append_keys "" 68 | if { $backup_type eq "UCS (User Configuration Set)" } { 69 | set create_backup_command "tmsh::save /sys ucs" 70 | set backup_directory /var/local/ucs 71 | # Backup passphrase usage 72 | if { $::backup_type__backup_passphrase_select eq "Yes" } { 73 | set backup_passphrase $::backup_type__backup_passphrase 74 | set create_backup_command_append_pass "passphrase $backup_passphrase" 75 | } 76 | # Backup private key inclusion 77 | if { $::backup_type__backup_includeprivatekeys eq "No" } { 78 | set create_backup_command_append_keys "no-private-key" 79 | } 80 | set backup_file_name "" 81 | set backup_file_name_extension ".ucs" 82 | set backup_file_script_extension ".ucs" 83 | } 84 | elseif { $backup_type eq "SCF (Single Configuration File)" } { 85 | set create_backup_command "tmsh::save /sys config file" 86 | set backup_directory /var/local/scf 87 | set backup_file_name_extension ".scf" 88 | set backup_file_script_extension ".scf" 89 | } 90 | 91 | set freq $::backup_schedule__frequency_select 92 | 93 | if { $freq != "Disable" } { 94 | # Ensure a default $filename_format is set 95 | if { $::destination_parameters__filename_format eq "" } { 96 | set filename_format {${host}_%Y%m%d_%H%M%S} 97 | } 98 | else { 99 | set filename_format [lindex [split $::destination_parameters__filename_format " "] 0] 100 | } 101 | 102 | if { $::destination_parameters__protocol_enable eq "Remotely via SCP/SFTP" } { 103 | # Get the F5 Master key 104 | set f5masterkey [exec f5mku -K] 105 | # Store the target server information securely, encrypted with the unit key 106 | set encryptedusername [exec echo "$::destination_parameters__scp_remote_username" | openssl aes-256-ecb -salt -a -A -k ${f5masterkey}] 107 | set encryptedserver [exec echo "$::destination_parameters__scp_remote_server" | openssl aes-256-ecb -salt -a -A -k ${f5masterkey}] 108 | set encrypteddirectory [exec echo "$::destination_parameters__scp_remote_directory" | openssl aes-256-ecb -salt -a -A -k ${f5masterkey}] 109 | # Clean the private key data before cleanup 110 | set cleaned_privatekey [exec echo "$::destination_parameters__scp_sshprivatekey" | sed -e "s/BEGIN RSA PRIVATE KEY/BEGIN;RSA;PRIVATE;KEY/g" -e "s/END RSA PRIVATE KEY/END;RSA;PRIVATE;KEY/g" -e "s/ /\\\n/g" -e "s/;/ /g"] 111 | # Encrypt the private key data before dumping to a file 112 | set encrypted_privatekey [exec echo "$cleaned_privatekey" | openssl aes-256-ecb -salt -a -A -k ${f5masterkey}] 113 | # Set optional cipher for SCP (e.g. aes256-gcm@openssh.com) 114 | if { "$::destination_parameters__scp_cipher" equals "" } { 115 | set scp_cipher "" 116 | } else { 117 | set scp_cipher "-c $::destination_parameters__scp_cipher" 118 | } 119 | # Set optional "StrictHostKeyChecking=no" 120 | if { "$::destination_parameters__scp_stricthostkeychecking" equals "Yes" } { 121 | set scp_stricthostkeychecking "-o StrictHostKeyChecking=yes" 122 | } else { 123 | set scp_stricthostkeychecking "-o StrictHostKeyChecking=no" 124 | } 125 | # Create the iCall action 126 | set script { 127 | exec echo "f5.automated_backup iApp TMSHAPPNAME: STARTED" >> /var/tmp/scriptd.out 128 | exec logger -p local0.info "f5.automated_backup iApp TMSHAPPNAME: STARTED" 129 | # Get the hostname of the device we're running on 130 | set host [tmsh::get_field_value [lindex [tmsh::get_config sys global-settings] 0] hostname] 131 | # Get the current date and time in a specific format 132 | set cdate [clock format [clock seconds] -format "FORMAT"] 133 | # Form the filename for the backup 134 | set fname_noext "${cdate}" 135 | set fname "${cdate}BACKUPFILENAMEXTENSION" 136 | # Run the 'create backup' command 137 | exec echo "f5.automated_backup iApp TMSHAPPNAME: $fname GENERATING" >> /var/tmp/scriptd.out 138 | exec logger -p local0.info "f5.automated_backup iApp TMSHAPPNAME: $fname GENERATING" 139 | # Delay 1 second to allow proper logging to /var/tmp/scriptd.out 140 | exec sleep 1 141 | BACKUPCOMMAND $fname BACKUPAPPEND_PASS BACKUPAPPEND_KEYS 142 | exec echo "f5.automated_backup iApp TMSHAPPNAME: $fname SAVED LOCALLY (BACKUPDIRECTORY)" >> /var/tmp/scriptd.out 143 | exec logger -p local0.info "f5.automated_backup iApp TMSHAPPNAME: $fname SAVED LOCALLY (BACKUPDIRECTORY)" 144 | # Set the script filename 145 | set scriptfile "/var/tmp/f5.automated_backup__TMSHAPPNAME_scp.sh" 146 | # Clean, recreate, and run a custom bash script that will perform the SCP upload 147 | exec rm -f $scriptfile 148 | exec echo "yes" 149 | exec echo -e "scp_function()\n{\n\tf5masterkey=\$(f5mku -K)\n\tusername=\$(echo \"ENCRYPTEDUSERNAME\" | openssl aes-256-ecb -salt -a -A -d -k \${f5masterkey})\n\tserver=\$(echo \"ENCRYPTEDSERVER\" | openssl aes-256-ecb -salt -a -A -d -k \${f5masterkey})\n\tdirectory=\$(echo \"ENCRYPTEDDIRECTORY\" | openssl aes-256-ecb -salt -a -A -d -k \${f5masterkey})\n\techo \"ENCRYPTEDPRIVATEKEY\" | openssl aes-256-ecb -salt -a -A -d -k \${f5masterkey} > /var/tmp/TMSHAPPNAME_scp.key\n\n\tchmod 600 /var/tmp/TMSHAPPNAME_scp.key\n\tscp -i /var/tmp/TMSHAPPNAME_scp.key SCPCIPHER SCPSTRICTHOSTKEYCHECKING BACKUPDIRECTORY/${fname_noext}BACKUPFILESCRIPTEXTENSION \${username}@\${server}:\${directory} 2>> /var/tmp/scriptd.out\n\tscp_result=\$?\n\trm -f /var/tmp/TMSHAPPNAME_scp.key\n\treturn \$scp_result\n}\n\nscp_function" > $scriptfile 150 | exec chmod +x $scriptfile 151 | exec echo "f5.automated_backup iApp TMSHAPPNAME: $fname REMOTE COPY (SCP) STARTING" >> /var/tmp/scriptd.out 152 | exec logger -p local0.info "f5.automated_backup iApp TMSHAPPNAME: $fname REMOTE COPY (SCP) STARTING" 153 | if { [catch {exec $scriptfile}] } { 154 | exec echo "f5.automated_backup iApp TMSHAPPNAME: $fname REMOTE COPY (SCP) FAILED (check for errors above)" >> /var/tmp/scriptd.out 155 | exec logger -p local0.crit "f5.automated_backup iApp TMSHAPPNAME: $fname REMOTE COPY (SCP) FAILED (see /var/tmp/scriptd.out for errors)" 156 | } else { 157 | exec echo "f5.automated_backup iApp TMSHAPPNAME: $fname REMOTE COPY (SCP) SUCCEEDED" >> /var/tmp/scriptd.out 158 | exec logger -p local0.notice "f5.automated_backup iApp TMSHAPPNAME: $fname REMOTE COPY (SCP) SUCCEEDED" 159 | } 160 | # Clean up local files 161 | exec rm -f $scriptfile 162 | exec rm -f /var/tmp/TMSHAPPNAME_scp.key 163 | exec rm -f BACKUPDIRECTORY/${fname_noext}BACKUPFILESCRIPTEXTENSION 164 | exec echo "f5.automated_backup iApp TMSHAPPNAME: FINISHED" >> /var/tmp/scriptd.out 165 | exec logger -p local0.info "f5.automated_backup iApp TMSHAPPNAME: FINISHED" 166 | } 167 | # Swap many variables into $script; due to the curly braces used to initially set $script, any referenced variables will *not* be expanded simply by deploying the iApp. 168 | set script [string map [list FORMAT $filename_format BACKUPFILENAMEXTENSION $backup_file_name_extension BACKUPFILESCRIPTEXTENSION $backup_file_script_extension BACKUPDIRECTORY $backup_directory BACKUPCOMMAND $create_backup_command BACKUPAPPEND_PASS $create_backup_command_append_pass BACKUPAPPEND_KEYS $create_backup_command_append_keys TMSHAPPNAME $tmsh::app_name ENCRYPTEDUSERNAME $encryptedusername ENCRYPTEDSERVER $encryptedserver ENCRYPTEDDIRECTORY $encrypteddirectory ENCRYPTEDPRIVATEKEY $encrypted_privatekey SCPCIPHER $scp_cipher SCPSTRICTHOSTKEYCHECKING $scp_stricthostkeychecking] $script] 169 | } 170 | elseif { $::destination_parameters__protocol_enable eq "Remotely via FTP" } { 171 | # Get the F5 Master key 172 | set f5masterkey [exec f5mku -K] 173 | # Store the target server information securely, encrypted with the unit key 174 | set encryptedusername [exec echo "$::destination_parameters__ftp_remote_username" | openssl aes-256-ecb -salt -a -A -k ${f5masterkey}] 175 | set encryptedpassword [exec echo "$::destination_parameters__ftp_remote_password" | openssl aes-256-ecb -salt -a -A -k ${f5masterkey}] 176 | set encryptedserver [exec echo "$::destination_parameters__ftp_remote_server" | openssl aes-256-ecb -salt -a -A -k ${f5masterkey}] 177 | set encrypteddirectory [exec echo "$::destination_parameters__ftp_remote_directory" | openssl aes-256-ecb -salt -a -A -k ${f5masterkey}] 178 | # Create the iCall action 179 | set script { 180 | exec echo "f5.automated_backup iApp TMSHAPPNAME: STARTED" >> /var/tmp/scriptd.out 181 | exec logger -p local0.info "f5.automated_backup iApp TMSHAPPNAME: STARTED" 182 | # Get the hostname of the device we're running on 183 | set host [tmsh::get_field_value [lindex [tmsh::get_config sys global-settings] 0] hostname] 184 | # Get the current date and time in a specific format 185 | set cdate [clock format [clock seconds] -format "FORMAT"] 186 | # Form the filename for the backup 187 | set fname_noext "${cdate}" 188 | set fname "${cdate}BACKUPFILENAMEXTENSION" 189 | # Run the 'create backup' command 190 | exec echo "f5.automated_backup iApp TMSHAPPNAME: $fname GENERATING" >> /var/tmp/scriptd.out 191 | exec logger -p local0.info "f5.automated_backup iApp TMSHAPPNAME: $fname GENERATING" 192 | # Delay 1 second to allow proper logging to /var/tmp/scriptd.out 193 | exec sleep 1 194 | BACKUPCOMMAND $fname BACKUPAPPEND_PASS BACKUPAPPEND_KEYS 195 | exec echo "f5.automated_backup iApp TMSHAPPNAME: $fname SAVED LOCALLY (BACKUPDIRECTORY)" >> /var/tmp/scriptd.out 196 | exec logger -p local0.info "f5.automated_backup iApp TMSHAPPNAME: $fname SAVED LOCALLY (BACKUPDIRECTORY)" 197 | # Set the config file 198 | set configfile "/config/f5.automated_backup__TMSHAPPNAME_ftp.conf" 199 | # Set the script filename 200 | set scriptfile "/var/tmp/f5.automated_backup__TMSHAPPNAME_ftp.sh" 201 | # Clean, recreate, run and reclean a custom bash script that will perform the FTP upload 202 | exec rm -f $scriptfile 203 | # Updated command v2.2.4 to force binary transfer. 204 | exec echo -e "ftp_function()\n{\n\tf5masterkey=\$(f5mku -K)\n\tusername=\$(echo \"ENCRYPTEDUSERNAME\" | openssl aes-256-ecb -salt -a -A -d -k \${f5masterkey})\n\tpassword=\$(echo \"ENCRYPTEDPASSWORD\" | openssl aes-256-ecb -salt -a -A -d -k \${f5masterkey})\n\tserver=\$(echo \"ENCRYPTEDSERVER\" | openssl aes-256-ecb -salt -a -A -d -k \${f5masterkey})\n\tdirectory=\$(echo \"ENCRYPTEDDIRECTORY\" | openssl aes-256-ecb -salt -a -A -d -k \${f5masterkey})\n\n\tftp_return=\$(ftp -n \${server} << END_FTP\nquote USER \${username}\nquote PASS \${password}\nbinary\nput BACKUPDIRECTORY/${fname}BACKUPFILESCRIPTEXTENSION \${directory}/${fname}BACKUPFILESCRIPTEXTENSION\nquit\nEND_FTP\n)\n\tif \[ \"\$ftp_return\" == \"\" \]\n\tthen\n\t\treturn 0\n\telse\n\t\techo \"\$ftp_return\" >> /var/tmp/scriptd.out\n\t\treturn 1\n\tfi\n}\n\nftp_function" > $scriptfile 205 | # Original command which allowed ascii transfer. 206 | #exec echo -e "put()\n{\n\tfields=\"username password server directory\"\n\ti=1\n\tf5masterkey=\$(f5mku -K)\n\tfor current_field in \$fields ; do\n\t\tsedcommand=\"\${i}p\"\n\t\tcurrent_encrypted_value=\$(sed -n \"\$sedcommand\" $configfile)\n\t\tcurrent_decrypted_value=\$(echo \"\$current_encrypted_value\" | openssl aes-256-ecb -salt -a -d -k \$f5masterkey)\n\t\teval \"\$current_field=\$current_decrypted_value\"\n\t\tlet i=\$i+1\n\t\tunset current_encrypted_value current_decrypted_value sedcommand\n\tdone\n\tftp -n \${server} << END_FTP\nquote USER \${username}\nquote PASS \${password}\nput BACKUPDIRECTORY/${fname}BACKUPFILESCRIPTEXTENSION \${directory}/${fname}BACKUPFILESCRIPTEXTENSION\nquit\nEND_FTP\n\treturn \$?\n}\n\nput" > $scriptfile 207 | exec chmod +x $scriptfile 208 | exec echo "f5.automated_backup iApp TMSHAPPNAME: $fname REMOTE COPY (FTP) STARTING" >> /var/tmp/scriptd.out 209 | exec logger -p local0.info "f5.automated_backup iApp TMSHAPPNAME: $fname REMOTE COPY (FTP) STARTING" 210 | if { [catch {exec $scriptfile}] } { 211 | exec echo "f5.automated_backup iApp TMSHAPPNAME: $fname REMOTE COPY (FTP) FAILED (check for errors above)" >> /var/tmp/scriptd.out 212 | exec logger -p local0.crit "f5.automated_backup iApp TMSHAPPNAME: $fname REMOTE COPY (FTP) FAILED (see /var/tmp/scriptd.out for errors)" 213 | } else { 214 | exec echo "f5.automated_backup iApp TMSHAPPNAME: $fname REMOTE COPY (FTP) SUCCEEDED" >> /var/tmp/scriptd.out 215 | exec logger -p local0.notice "f5.automated_backup iApp TMSHAPPNAME: $fname REMOTE COPY (FTP) SUCCEEDED" 216 | } 217 | # Clean up local files 218 | exec rm -f $scriptfile 219 | exec rm -f BACKUPDIRECTORY/${fname_noext}BACKUPFILESCRIPTEXTENSION 220 | exec echo "f5.automated_backup iApp TMSHAPPNAME: FINISHED" >> /var/tmp/scriptd.out 221 | exec logger -p local0.info "f5.automated_backup iApp TMSHAPPNAME: FINISHED" 222 | } 223 | # Swap many variables into $script; due to the curly braces used to initially set $script, any referenced variables will *not* be expanded simply by deploying the iApp. 224 | set script [string map [list FORMAT $filename_format BACKUPFILENAMEXTENSION $backup_file_name_extension BACKUPFILESCRIPTEXTENSION $backup_file_script_extension BACKUPDIRECTORY $backup_directory BACKUPCOMMAND $create_backup_command BACKUPAPPEND_PASS $create_backup_command_append_pass BACKUPAPPEND_KEYS $create_backup_command_append_keys TMSHAPPNAME $tmsh::app_name ENCRYPTEDUSERNAME $encryptedusername ENCRYPTEDPASSWORD $encryptedpassword ENCRYPTEDSERVER $encryptedserver ENCRYPTEDDIRECTORY $encrypteddirectory] $script] 225 | } 226 | elseif { $::destination_parameters__protocol_enable eq "Remotely via SMB/CIFS" } { 227 | # Get the F5 Master key 228 | set f5masterkey [exec f5mku -K] 229 | # Store the target server information securely, encrypted with the unit key 230 | set encryptedusername [exec echo "$::destination_parameters__smb_remote_username" | openssl aes-256-ecb -salt -a -A -k ${f5masterkey}] 231 | set encryptedpassword [exec echo "$::destination_parameters__smb_remote_password" | openssl aes-256-ecb -salt -a -A -k ${f5masterkey}] 232 | set encryptedmsdomain [exec echo "$::destination_parameters__smb_remote_domain" | openssl aes-256-ecb -salt -a -A -k ${f5masterkey}] 233 | set encryptedserver [exec echo "$::destination_parameters__smb_remote_server" | openssl aes-256-ecb -salt -a -A -k ${f5masterkey}] 234 | set encryptedmsshare [exec echo "$::destination_parameters__smb_remote_path" | openssl aes-256-ecb -salt -a -A -k ${f5masterkey}] 235 | set encryptedmssubdir [exec echo "$::destination_parameters__smb_remote_directory" | openssl aes-256-ecb -salt -a -A -k ${f5masterkey}] 236 | set encryptedmountp [exec echo "$::destination_parameters__smb_local_mountdir" | openssl aes-256-ecb -salt -a -A -k ${f5masterkey}] 237 | # Create the iCall action 238 | set script { 239 | exec echo "f5.automated_backup iApp TMSHAPPNAME: STARTED" >> /var/tmp/scriptd.out 240 | exec logger -p local0.info "f5.automated_backup iApp TMSHAPPNAME: STARTED" 241 | # Get the hostname of the device we're running on 242 | set host [tmsh::get_field_value [lindex [tmsh::get_config sys global-settings] 0] hostname] 243 | # Get the current date and time in a specific format 244 | set cdate [clock format [clock seconds] -format "FORMAT"] 245 | # Form the filename for the backup 246 | set fname_noext "${cdate}" 247 | set fname "${cdate}BACKUPFILENAMEXTENSION" 248 | # Run the 'create backup' command 249 | exec echo "f5.automated_backup iApp TMSHAPPNAME: $fname GENERATING" >> /var/tmp/scriptd.out 250 | exec logger -p local0.info "f5.automated_backup iApp TMSHAPPNAME: $fname GENERATING" 251 | # Delay 1 second to allow proper logging to /var/tmp/scriptd.out 252 | exec sleep 1 253 | BACKUPCOMMAND $fname BACKUPAPPEND_PASS BACKUPAPPEND_KEYS 254 | exec echo "f5.automated_backup iApp TMSHAPPNAME: $fname SAVED LOCALLY (BACKUPDIRECTORY)" >> /var/tmp/scriptd.out 255 | exec logger -p local0.info "f5.automated_backup iApp TMSHAPPNAME: $fname SAVED LOCALLY (BACKUPDIRECTORY)" 256 | # Set the script filename 257 | set scriptfile "/var/tmp/f5.automated_backup__TMSHAPPNAME_smb.sh" 258 | # Clean, recreate, run and reclean a custom bash script that will perform the SMB upload 259 | exec rm -f $scriptfile 260 | exec echo -e "\#\!/bin/sh\nf5masterkey=\$(f5mku -K)\nusername=\$(echo \"ENCRYPTEDUSERNAME\" | openssl aes-256-ecb -salt -a -A -d -k \${f5masterkey})\npassword=\$(echo \"ENCRYPTEDPASSWORD\" | openssl aes-256-ecb -salt -a -A -d -k \${f5masterkey})\nmsdomain=\$(echo \"ENCRYPTEDMSDOMAIN\" | openssl aes-256-ecb -salt -a -A -d -k \${f5masterkey})\nserver=\$(echo \"ENCRYPTEDSERVER\" | openssl aes-256-ecb -salt -a -A -d -k \${f5masterkey})\nmsshare=\$(echo \"ENCRYPTEDMSSHARE\" | openssl aes-256-ecb -salt -a -A -d -k \${f5masterkey})\nmssubdir=\$(echo \"ENCRYPTEDMSSUBDIR\" | openssl aes-256-ecb -salt -a -A -d -k \${f5masterkey})\nmountp=\$(echo \"ENCRYPTEDMOUNTP\" | openssl aes-256-ecb -salt -a -A -d -k \${f5masterkey})\ncd /var/local/ucs\nif \[ \! -d \${mountp} \]\nthen\n\tmkdir -p \${mountp}\n\tif \[ \$? -ne 0 \]\n\tthen\n\t\trm -f ${fname_noext}BACKUPFILESCRIPTEXTENSION\n\t\texit 1\n\tfi\nfi\nmount -t cifs //\${server}/\${msshare} \${mountp} -o user=\${username}%\${password},domain=\${msdomain} 2>> /var/tmp/scriptd.out\nif \[ \$? -ne 0 \]\n\tthen\n\trm -f ${fname_noext}BACKUPFILESCRIPTEXTENSION\n\texit 1\nfi\nfONSMB=\$(ls -t \${mountp}\${mssubdir}/\*.ucs 2>/dev/null| head -n 1 2>/dev/null)\nif \[ \"X\"\${fONSMB} \!= \"X\" \]\n\tthen\n\tsum1=\$(md5sum ${fname_noext}BACKUPFILESCRIPTEXTENSION | awk '{print \$1}')\n\tsum2=\$(md5sum \${fONSMB} | awk \'{print \$1}\')\n\tif \[ \${sum1} == \${sum2} \]\n\tthen\n\t\techo \"ERROR: File ${fname_noext}BACKUPFILESCRIPTEXTENSION already exists in //\${server}/\${msshare}/\${mssubdir}\" >> /var/tmp/scriptd.out\n\t\tumount \${mountp}\n\t\trm -f ${fname_noext}BACKUPFILESCRIPTEXTENSION\n\t\texit 1\n\tfi\nfi\ncp ${fname_noext}BACKUPFILESCRIPTEXTENSION \${mountp}\${mssubdir}\nrm -f ${fname_noext}BACKUPFILESCRIPTEXTENSION\numount \${mountp}\n\nexit 0\n\n" > $scriptfile 261 | exec chmod +x $scriptfile 262 | exec echo "f5.automated_backup iApp TMSHAPPNAME: $fname STARTING REMOTE COPY (SMB/CIFS)" >> /var/tmp/scriptd.out 263 | exec logger -p local0.info "f5.automated_backup iApp TMSHAPPNAME: $fname REMOTE COPY (SMB/CIFS) STARTING" 264 | if { [catch {exec $scriptfile}] } { 265 | exec echo "f5.automated_backup iApp TMSHAPPNAME: $fname REMOTE COPY (SMB/CIFS) FAILED (check for errors above)" >> /var/tmp/scriptd.out 266 | exec logger -p local0.crit "f5.automated_backup iApp TMSHAPPNAME: $fname REMOTE COPY (SMB/CIFS) FAILED (see /var/tmp/scriptd.out for errors)" 267 | } else { 268 | exec echo "f5.automated_backup iApp TMSHAPPNAME: $fname REMOTE COPY (SMB/CIFS) SUCCEEDED" >> /var/tmp/scriptd.out 269 | exec logger -p local0.notice "f5.automated_backup iApp TMSHAPPNAME: $fname REMOTE COPY (SMB/CIFS) SUCCEEDED" 270 | } 271 | # Clean up local files 272 | exec rm -f $scriptfile 273 | exec rm -f BACKUPDIRECTORY/${fname_noext}BACKUPFILESCRIPTEXTENSION 274 | exec echo "f5.automated_backup iApp TMSHAPPNAME: FINISHED" >> /var/tmp/scriptd.out 275 | exec logger -p local0.info "f5.automated_backup iApp TMSHAPPNAME: FINISHED" 276 | } 277 | # Swap many variables into $script; due to the curly braces used to initially set $script, any referenced variables will *not* be expanded simply by deploying the iApp. 278 | set script [string map [list FORMAT $filename_format BACKUPFILENAMEXTENSION $backup_file_name_extension BACKUPFILESCRIPTEXTENSION $backup_file_script_extension BACKUPDIRECTORY $backup_directory BACKUPCOMMAND $create_backup_command BACKUPAPPEND_PASS $create_backup_command_append_pass BACKUPAPPEND_KEYS $create_backup_command_append_keys TMSHAPPNAME $tmsh::app_name ENCRYPTEDUSERNAME $encryptedusername ENCRYPTEDPASSWORD $encryptedpassword ENCRYPTEDMSDOMAIN $encryptedmsdomain ENCRYPTEDSERVER $encryptedserver ENCRYPTEDMSSHARE $encryptedmsshare ENCRYPTEDMSSUBDIR $encryptedmssubdir ENCRYPTEDMOUNTP $encryptedmountp] $script] 279 | } 280 | else { 281 | set script { 282 | exec echo "f5.automated_backup iApp TMSHAPPNAME: STARTED" >> /var/tmp/scriptd.out 283 | exec logger -p local0.info "f5.automated_backup iApp TMSHAPPNAME: STARTED" 284 | # Get the hostname of the device we're running on 285 | set host [tmsh::get_field_value [lindex [tmsh::get_config sys global-settings] 0] hostname] 286 | # Get the current date and time in a specific format 287 | set cdate [clock format [clock seconds] -format "FORMAT"] 288 | # Form the filename for the backup 289 | set fname "${cdate}BACKUPFILENAMEXTENSION" 290 | # Run the 'create backup' command 291 | exec echo "f5.automated_backup iApp TMSHAPPNAME: $fname GENERATING" >> /var/tmp/scriptd.out 292 | exec logger -p local0.info "f5.automated_backup iApp TMSHAPPNAME: $fname GENERATING" 293 | # Delay 1 second to allow proper logging to /var/tmp/scriptd.out 294 | exec sleep 1 295 | BACKUPCOMMAND $fname BACKUPAPPEND_PASS BACKUPAPPEND_KEYS 296 | exec echo "f5.automated_backup iApp TMSHAPPNAME: $fname SAVED LOCALLY (BACKUPDIRECTORY)" >> /var/tmp/scriptd.out 297 | exec logger -p local0.info "f5.automated_backup iApp TMSHAPPNAME: $fname SAVED LOCALLY (BACKUPDIRECTORY)" 298 | exec echo "f5.automated_backup iApp TMSHAPPNAME: FINISHED" >> /var/tmp/scriptd.out 299 | exec logger -p local0.info "f5.automated_backup iApp TMSHAPPNAME: FINISHED" 300 | } 301 | # Swap many variables into $script; due to the curly braces used to initially set $script, any referenced variables will *not* be expanded simply by deploying the iApp. 302 | set script [string map [list FORMAT $filename_format BACKUPFILENAMEXTENSION $backup_file_name_extension BACKUPFILESCRIPTEXTENSION $backup_file_script_extension BACKUPDIRECTORY $backup_directory BACKUPCOMMAND $create_backup_command BACKUPAPPEND_PASS $create_backup_command_append_pass BACKUPAPPEND_KEYS $create_backup_command_append_keys TMSHAPPNAME $tmsh::app_name] $script] 303 | } 304 | 305 | iapp::conf create sys icall script f5.automated_backup__${tmsh::app_name} definition \{ $script \} 306 | 307 | ## Get time info for setting first-occurrence on daily handler from iApp input 308 | #Create the handlers 309 | if { $freq eq "Every X Minutes" } { 310 | set everyxminutes $::backup_schedule__everyxminutes_value 311 | set interval [expr $everyxminutes*60] 312 | set cdate [clock format [clock seconds] -format "%Y-%m-%d:%H:%M"] 313 | iapp::conf create sys icall handler periodic f5.automated_backup__${tmsh::app_name}-handler \{ \ 314 | interval $interval \ 315 | first-occurrence $cdate:00 \ 316 | script f5.automated_backup__${tmsh::app_name} \} 317 | } 318 | elseif { $freq eq "Every X Hours" } { 319 | set everyxhours $::backup_schedule__everyxhours_value 320 | set interval [expr $everyxhours*3600] 321 | set minutes $::backup_schedule__everyxhours_min_select 322 | set cdate [clock format [clock seconds] -format "%Y-%m-%d:%H"] 323 | iapp::conf create sys icall handler periodic f5.automated_backup__${tmsh::app_name}-handler \{ \ 324 | interval $interval \ 325 | first-occurrence $cdate:$minutes:00 \ 326 | script f5.automated_backup__${tmsh::app_name} \} 327 | } 328 | elseif { $freq eq "Every X Days" } { 329 | set everyxdays $::backup_schedule__everyxdays_value 330 | set interval [expr $everyxdays*86400] 331 | set hours [lindex [split $::backup_schedule__everyxdays_time ":"] 0] 332 | set minutes [lindex [split $::backup_schedule__everyxdays_time ":"] 1] 333 | set cdate [clock format [clock seconds] -format "%Y-%m-%d"] 334 | iapp::conf create sys icall handler periodic f5.automated_backup__${tmsh::app_name}-handler \{ \ 335 | interval $interval \ 336 | first-occurrence $cdate:$hours:$minutes:00 \ 337 | script f5.automated_backup__${tmsh::app_name} \} 338 | } 339 | elseif { $freq eq "Every X Weeks" } { 340 | set everyxweeks $::backup_schedule__everyxweeks_value 341 | set interval [expr $everyxweeks*604800] 342 | set hours [lindex [split $::backup_schedule__everyxweeks_time ":"] 0] 343 | set minutes [lindex [split $::backup_schedule__everyxweeks_time ":"] 1] 344 | ## Get day of week info for setting first-occurrence on weekly handler from iApp input 345 | array set dowmap { 346 | Sunday 0 347 | Monday 1 348 | Tuesday 2 349 | Wednesday 3 350 | Thursday 4 351 | Friday 5 352 | Saturday 6 353 | } 354 | set sday_name $::backup_schedule__everyxweeks_dow_select 355 | set sday_num $dowmap($sday_name) 356 | set cday_name [clock format [clock seconds] -format "%A"] 357 | set cday_num $dowmap($cday_name) 358 | set date_offset [expr 86400*($sday_num - $cday_num)] 359 | set date_final [clock format [expr [clock seconds] + $date_offset] -format "%Y-%m-%d"] 360 | iapp::conf create sys icall handler periodic f5.automated_backup__${tmsh::app_name}-handler \{ \ 361 | interval $interval \ 362 | first-occurrence $date_final:$hours:$minutes:00 \ 363 | script f5.automated_backup__${tmsh::app_name} \} 364 | } 365 | elseif { $freq eq "Every X Months" } { 366 | set everyxmonths $::backup_schedule__everyxmonths_value 367 | set interval [expr 60*60*24*365] 368 | set dom $::backup_schedule__everyxmonths_dom_select 369 | set hours [lindex [split $::backup_schedule__everyxmonths_time ":"] 0] 370 | set minutes [lindex [split $::backup_schedule__everyxmonths_time ":"] 1] 371 | for { set month 1 } { $month < 13 } { set month [expr $month+$everyxmonths] } { 372 | set cdate [clock format [clock seconds] -format "%Y-$month-$dom"] 373 | iapp::conf create sys icall handler periodic f5.automated_backup__${tmsh::app_name}-month_${month}-handler \{ \ 374 | interval $interval \ 375 | first-occurrence $cdate:$hours:$minutes:00 \ 376 | script f5.automated_backup__${tmsh::app_name} \} 377 | } 378 | } 379 | elseif { $freq eq "Custom" } { 380 | set hours [lindex [split $::backup_schedule__custom_time ":"] 0] 381 | set minutes [lindex [split $::backup_schedule__custom_time ":"] 1] 382 | ## Get day of week info for setting first-occurrence on weekly handler from iApp input 383 | array set dowmap { 384 | Sunday 0 385 | Monday 1 386 | Tuesday 2 387 | Wednesday 3 388 | Thursday 4 389 | Friday 5 390 | Saturday 6 391 | } 392 | foreach sday_name $::backup_schedule__custom_dow_select { 393 | set sday_num $dowmap($sday_name) 394 | set cday_name [clock format [clock seconds] -format "%A"] 395 | set cday_num $dowmap($cday_name) 396 | set date_offset [expr 86400*($sday_num - $cday_num)] 397 | set date_final [clock format [expr [clock seconds] + $date_offset] -format "%Y-%m-%d"] 398 | iapp::conf create sys icall handler periodic f5.automated_backup__${tmsh::app_name}-handler-$sday_name \{ \ 399 | interval 604800 \ 400 | first-occurrence $date_final:$hours:$minutes:00 \ 401 | script f5.automated_backup__${tmsh::app_name} \} 402 | } 403 | } 404 | else { 405 | 406 | } 407 | 408 | ## Automatic Pruning handler 409 | if { $::destination_parameters__protocol_enable eq "On this F5" } { 410 | set autoprune $::destination_parameters__pruning_enable 411 | if { $autoprune eq "Yes" } { 412 | set prune_conserve $::destination_parameters__keep_amount 413 | set today [clock format [clock seconds] -format "%Y-%m-%d"] 414 | set script { 415 | # Get the hostname of the device we're running on 416 | set host [tmsh::get_field_value [lindex [tmsh::get_config sys global-settings] 0] hostname] 417 | # Set the script filename 418 | set scriptfile "/var/tmp/autopruning.sh" 419 | # Clean, recreate, run and reclean a custom bash script that will perform the pruning 420 | exec rm -f $scriptfile 421 | exec echo -e "files_tokeep=\$(ls -t /var/local/ucs/*.ucs | head -n CONSERVE\)\nfor current_ucs_file in `ls /var/local/ucs/*.ucs` ; do\n\tcurrent_ucs_file_basename=`basename \$current_ucs_file`\n\tcheck_file=\$(echo \$files_tokeep | grep -w \$current_ucs_file_basename)\n\tif \[ \"\$check_file\" == \"\" \] ; then\n\t\trm -f \$current_ucs_file\n\tfi\ndone" > $scriptfile 422 | exec chmod +x $scriptfile 423 | exec $scriptfile 424 | exec rm -f $scriptfile 425 | } 426 | set script [string map [list CONSERVE $prune_conserve] $script] 427 | iapp::conf create sys icall script f5.automated_backup__${tmsh::app_name}_pruning definition \{ $script \} 428 | set cdate [clock format [clock seconds] -format "%Y-%m-%d:%H:%M"] 429 | # Interval can be increased as needed if pruning every minute is problematic 430 | iapp::conf create sys icall handler periodic f5.automated_backup__${tmsh::app_name}_pruning-handler \{ \ 431 | interval 60 \ 432 | first-occurrence $cdate:00 \ 433 | script f5.automated_backup__${tmsh::app_name}_pruning \} 434 | } 435 | } 436 | } 437 | 438 | iapp::template end 439 | } 440 | macro { 441 | } 442 | presentation { 443 | section deployment_info { 444 | message deployment_info_first_time "Deploying the iApp may not trigger an immediate backup." 445 | message deployment_info_updates "For testing, to force the iApp to run an immediate backup it is easiest to set the Backup Schedule to 'Every X Minutes' and simply change value of 'X equals. Redeploying the iApp will not trigger an immediate backup unless the iCall handler is recreated and the first-occurrence value is set to a time before the moment of redeployment. When testing is complete, set the Backup Schedule to the desired ongoing schedule." 446 | message deployment_info_logs "The general log for all iApps is '/var/tmp/scriptd.out'. This iApp adds run logs and errors to '/var/tmp/scriptd.out'. Additionally, this iApp sends run logs (not full error messages) to '/var/log/ltm' (compatible with BIG-IP Remote Logging configuration)." 447 | } 448 | section backup_type { 449 | choice backup_type_select display "xlarge" { "UCS (User Configuration Set)", "SCF (Single Configuration File)" } 450 | optional ( backup_type_select == "SCF (Single Configuration File)" ) { 451 | message backup_help_scf "WARNING: Beware of choosing SCF file as not all configuration is included therein. Please check out SOL13408 (http://support.f5.com/kb/en-us/solutions/public/13000/400/sol13408.html) for more information." 452 | } 453 | optional ( backup_type_select == "UCS (User Configuration Set)" ) { 454 | choice backup_passphrase_select display "small" { "Yes", "No" } 455 | optional ( backup_passphrase_select == "Yes" ) { 456 | message backup_help_passphrase "WARNING: Losing the passphase will render the archives unusable. The encrypted UCS archive will be a PGP encoded file, *not* simply a tar.gz with a password on it." 457 | password backup_passphrase required display "large" 458 | } 459 | choice backup_includeprivatekeys display "small" { "Yes", "No" } 460 | optional ( backup_includeprivatekeys == "No" ) { 461 | message backup_help_privatekeys "WARNING: A UCS archive that does not contain the private keys CANNOT be used for restoring the device. It should be used for transfers to external services to whom you do not wish to disclose the private keys." 462 | } 463 | } 464 | } 465 | section backup_schedule { 466 | choice frequency_select display "large" { "Disable", "Every X Minutes", "Every X Hours", "Every X Days", "Every X Weeks", "Every X Months", "Custom" } 467 | optional ( frequency_select == "Every X Minutes" ) { 468 | editchoice everyxminutes_value default "30" display "small" { "1", "2", "5", "10", "15", "20", "30", "45", "60" } 469 | } 470 | optional ( frequency_select == "Every X Hours" ) { 471 | editchoice everyxhours_value default "1" display "small" { "1", "2", "3", "4", "6", "12", "24" } 472 | choice everyxhours_min_select display "small" tcl { 473 | for { set x 0 } { $x < 60 } { incr x } { 474 | append mins "$x\n" 475 | } 476 | return $mins 477 | } 478 | } 479 | optional ( frequency_select == "Every X Days" ) { 480 | editchoice everyxdays_value default "1" display "small" { "1", "2", "3", "4", "5", "7", "14" } 481 | string everyxdays_time required display "medium" 482 | } 483 | optional ( frequency_select == "Every X Weeks" ) { 484 | editchoice everyxweeks_value default "1" display "small" { "1", "2", "3", "4", "5", "7", "14" } 485 | choice everyxweeks_dow_select default "Sunday" display "medium" { "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday" } 486 | string everyxweeks_time required display "small" 487 | } 488 | optional ( frequency_select == "Every X Months" ) { 489 | editchoice everyxmonths_value default "1" display "small" { "1", "2", "3", "6", "12" } 490 | choice everyxmonths_dom_select display "small" tcl { 491 | for { set x 1 } { $x < 31 } { incr x } { 492 | append days "$x\n" 493 | } 494 | return $days 495 | } 496 | string everyxmonths_time required display "small" 497 | } 498 | optional ( frequency_select == "Custom" ) { 499 | multichoice custom_dow_select default {"Sunday"} display "medium" { "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday" } 500 | string custom_time required display "small" 501 | } 502 | } 503 | optional ( backup_schedule.frequency_select != "Disable" ) { 504 | section destination_parameters { 505 | choice protocol_enable display "xlarge" { "On this F5", "Remotely via SCP/SFTP", "Remotely via SMB/CIFS", "Remotely via FTP" } 506 | optional ( protocol_enable == "Remotely via SCP/SFTP") { 507 | message scp_sftp_help "A connection to an SSH server can be establish using both SCP and SFTP. SCP is more efficient for copying files to a remote network destination while, for interactive sessions, the SFTP protocol offers more features. This iApp uses SCP." 508 | string scp_remote_server required display "medium" validator "IpAddress" 509 | message scp_remote_server_help "IMPORTANT: Check '/root/.ssh/known_hosts' on each BIG-IP (including HA peers) to ensure the Destination IP above is listed. On each BIG-IP that does not list the Destination IP, connect directly to the Destination IP using the scp or ssh command. You will be asked to verify the 'RSA key fingerprint'. Entering 'yes' will store the fingerprint in '/root/.ssh/known_hosts' and allow subsequent connections without further verification. If IP from the CLI on all BIG-IPs (including HA peers) and verify/accept the fingerprint which should add an entry to the known_hosts file." 510 | choice scp_stricthostkeychecking default "Yes" display "large" { "Yes", "No (INSECURE)" } 511 | optional ( scp_stricthostkeychecking == "No (INSECURE)" ) { 512 | message scp_stricthostkeychecking_warning1 "WARNING: Selecting 'No (INSECURE)' will ignore certificate verification for connections this iApp makes to the server configured above. Backups could be copied to an unintended server, including one owned by a bad actor." 513 | } 514 | message scp_stricthostkeychecking_help1 "It is MOST SECURE to select Yes, which is the SCP/SSH default setting and which will not allow connections to unknown servers. A server is considered 'unknown' until an SSH key fingerprint has been verified, or if the destination SSL certificate changes and the fingerprint no longer matches." 515 | optional ( scp_stricthostkeychecking == "Yes" ) { 516 | message scp_stricthostkeychecking_help2 "Selecting 'No (INSECURE)' will ignore certificate verification for connections this iApp makes to the server configured above." 517 | message scp_stricthostkeychecking_trouble1 "TROUBLESHOOTING: If the SCP script fails with a 'Host key verification failed' or 'No RSA host key is known for' error (which can viewed in /var/tmp/scriptd.out after deploying this iApp), review the IMPORTANT steps (under Destination IP) above regarding the known_hosts file to resolve the issue. Also, review additional troubleshooting notes." 518 | message scp_stricthostkeychecking_trouble2 "TROUBLESHOOTING: If the SCP script fails with a 'WARNING: REMOTE HOST IDENTIFICATION HAS CHANGED!' error (which can viewed in /var/tmp/scriptd.out after deploying this iApp), the certificate on the destination server has changed. This could mean 1) The certificate was updated legitimately, or 2) There is an IP conflict and the script is connecting to the wrong server, or 3) the destination server was replaced or rebuilt and has a new certificate, or 4) a bad actor is intercepting the connection (man-in-the-middle) and the script is rightly warning you to not connect. Investigate the destination server before proceeding." 519 | } 520 | string scp_remote_username required display "medium" 521 | password scp_sshprivatekey required display "large" 522 | message scp_encrypted_field_storage_help "Private key must be non-encrypted and in 'OpenSSH' base64 format. As an example run 'ssh-keygen -t -b 2048 -o -a 100' from the CLI, step through the questions, and view the resulting private key (by default ssh-keygen will save the key to ~/.ssh/id_rsa)." 523 | message scp_encrypted_field_storage_help2 "Passwords and private keys are stored in an encrypted format. The salt for the encryption algorithm is the F5 cluster's Master Key. The master key is not shared when exporting a qkview or UCS, thus rendering your passwords and private keys safe if a backup file were to be stored off-box." 524 | editchoice scp_cipher display "xlarge" { "aes128-ctr", "aes192-ctr", "aes256-ctr", "aes128-gcm@openssh.com", "chacha20-poly1305@openssh.com" } 525 | message scp_cipher_help "Depending on the version of F5 TMOS and the ssh configuration of the destination server, there may be no matching ciphers resulting in a 'no matching cipher found' error (which can viewed in /var/tmp/scriptd.out after deploying this iApp or it can be tested/demonstrated by attempting an scp or ssh connection from this device to the destination server). Find the word 'server' in the error and note the ciphers listed; select one of these ciphers from the list above or paste in one not listed." 526 | string scp_remote_directory display "medium" 527 | } 528 | optional ( protocol_enable == "Remotely via SMB/CIFS") { 529 | string smb_remote_server required display "medium" validator "IpAddress" 530 | message smb_remote_server_help "Ensure this Destination IP is reachable on port 139." 531 | string smb_remote_domain required display "medium" 532 | message smb_remote_domain_help "Start by entering the NetBIOS/Pre-Windows 2000 domain name; the fully qualified DNS domain name may work or be required in some environments." 533 | string smb_remote_username required display "medium" 534 | password smb_remote_password display "medium" 535 | message smb_remote_password_help "Special characters within passwords must be escaped (add a backslash before each special character as you input the password)." 536 | message smb_remote_password_help2 "Passwords and private keys are stored in an encrypted format. The salt for the encryption algorithm is the F5 cluster's Master Key. The master key is not shared when exporting a qkview or UCS, thus rendering your passwords and private keys safe if a backup file were to be stored off-box." 537 | string smb_remote_path required display "medium" 538 | message smb_remote_path_help "SMB share on a remote server. Do not include leading and trailing slashes. If the full share path is //SERVER/SHARE, enter SHARE in this field. If the full share path is //SERVER/PATH/SHARE, enter PATH/SHARE in this field." 539 | string smb_remote_directory display "medium" 540 | message smb_remote_directory_help "Relative path inside the SMB share to copy the file. Leave this field empty to store in root of SMB share. Include one leading slash and no trailing slashes. If the target directory is //SERVER/SHARE/PATH/DIRECTORY, enter /PATH/DIRECTORY in this field." 541 | string smb_local_mountdir required default "/var/tmp/cifs" display "medium" 542 | message smb_local_mountdir_help "Read-Write path on local F5 where SMB share will be mounted. Include one leading slash and no trailing slashes, for example /var/tmp/cifs" 543 | } 544 | optional ( protocol_enable == "Remotely via FTP") { 545 | string ftp_remote_server required display "medium" validator "IpAddress" 546 | string ftp_remote_username required display "medium" 547 | password ftp_remote_password display "medium" 548 | message ftp_encrypted_field_storage_help "Passwords and private keys are stored in an encrypted format. The salt for the encryption algorithm is the F5 cluster's Master Key. The master key is not shared when exporting a qkview or UCS, thus rendering your passwords and private keys safe if a backup file were to be stored off-box." 549 | string ftp_remote_directory display "medium" 550 | } 551 | editchoice filename_format display "xxlarge" tcl { 552 | set host [tmsh::get_field_value [lindex [tmsh::get_config sys global-settings] 0] hostname] 553 | set formats "" 554 | append formats {%Y%m%d%H%M%S_${host} => } 555 | append formats [clock format [clock seconds] -format "%Y%m%d%H%M%S_${host}"] 556 | append formats "\n" 557 | append formats {%Y%m%d_%H%M%S_${host} => } 558 | append formats [clock format [clock seconds] -format "%Y%m%d_%H%M%S_${host}"] 559 | append formats "\n" 560 | append formats {%Y%m%d_${host} => } 561 | append formats [clock format [clock seconds] -format "%Y%m%d_${host}"] 562 | append formats "\n" 563 | append formats {${host}_%Y%m%d%H%M%S => } 564 | append formats [clock format [clock seconds] -format "${host}_%Y%m%d%H%M%S"] 565 | append formats "\n" 566 | append formats {${host}_%Y%m%d_%H%M%S => } 567 | append formats [clock format [clock seconds] -format "${host}_%Y%m%d_%H%M%S"] 568 | append formats "\n" 569 | append formats {${host}_%Y%m%d => } 570 | append formats [clock format [clock seconds] -format "${host}_%Y%m%d"] 571 | append formats "\n" 572 | return $formats 573 | } 574 | message filename_format_help "You can select one, or create your own with all the [clock format] wildcards available in the tcl language, plus ${host} for the hostname. (http://www.tcl.tk/man/tcl8.6/TclCmd/clock.htm)" 575 | optional ( protocol_enable == "On this F5" ) { 576 | choice pruning_enable display "small" { "No", "Yes" } 577 | optional ( pruning_enable == "Yes" ) { 578 | editchoice keep_amount display "small" { "1", "2", "3", "4", "5", "6", "7", "8", "9", "10" } 579 | message pruning_help "Warning: if you decide to manually create a backupfile in the default directory, the automatic pruning will clean it if it doesn't match the 'newest X files' in that directory." 580 | } 581 | } 582 | } 583 | } 584 | text { 585 | deployment_info "Deployment Information" 586 | deployment_info.deployment_info_first_time "First Time Deployment:" 587 | deployment_info.deployment_info_updates "Testing the iApp:" 588 | deployment_info.deployment_info_logs "Logging:" 589 | backup_type "Backup Type" 590 | backup_type.backup_type_select "Select the type of backup:" 591 | backup_type.backup_passphrase_select "Use a passphrase to encrypt the UCS archive:" 592 | backup_type.backup_passphrase "What is the passphrase you want to use?" 593 | backup_type.backup_includeprivatekeys "Include the private keys in the archives?" 594 | backup_type.backup_help_scf "" 595 | backup_type.backup_help_passphrase "" 596 | backup_type.backup_help_privatekeys "" 597 | backup_schedule "Backup Schedule" 598 | backup_schedule.frequency_select "Frequency:" 599 | backup_schedule.everyxminutes_value "Where X equals:" 600 | backup_schedule.everyxhours_value "Where X equals:" 601 | backup_schedule.everyxhours_min_select "At what minute of each X hours should the backup occur?" 602 | backup_schedule.everyxdays_value "Where X equals:" 603 | backup_schedule.everyxdays_time "At what time on each X days should the backup occur? (Ex.: 15:25)" 604 | backup_schedule.everyxweeks_value "Where X equals:" 605 | backup_schedule.everyxweeks_time "At what time on the chosen day of each X weeks should the backup occur? (e.g. 04:15, 21:30)" 606 | backup_schedule.everyxweeks_dow_select "On what day of each X weeks should the backup should occur:" 607 | backup_schedule.everyxmonths_value "Where X equals:" 608 | backup_schedule.everyxmonths_time "At what time on the chosen day of each X months should the backup occur? (e.g. 04:15, 21:30)" 609 | backup_schedule.everyxmonths_dom_select "On what day of each X months should the backup should occur:" 610 | backup_schedule.custom_time "At what time on each selected day should the backup occur? (e.g. 04:15, 21:30)" 611 | backup_schedule.custom_dow_select "Choose the days of the week the backup should occur:" 612 | destination_parameters "Destination Parameters" 613 | destination_parameters.protocol_enable "Where do the backup files need to be saved?" 614 | destination_parameters.scp_sftp_help "SCP or SFTP?" 615 | destination_parameters.scp_remote_server "Destination IP:" 616 | destination_parameters.scp_remote_server_help "" 617 | destination_parameters.scp_stricthostkeychecking "StrictHostKeyChecking" 618 | destination_parameters.scp_stricthostkeychecking_help1 "" 619 | destination_parameters.scp_stricthostkeychecking_help2 "" 620 | destination_parameters.scp_stricthostkeychecking_trouble1 "" 621 | destination_parameters.scp_stricthostkeychecking_trouble2 "" 622 | destination_parameters.scp_stricthostkeychecking_warning1 "" 623 | destination_parameters.scp_remote_username "Username:" 624 | destination_parameters.scp_sshprivatekey "Copy/Paste the SSH private key to be used for passwordless authentication:" 625 | destination_parameters.scp_encrypted_field_storage_help "" 626 | destination_parameters.scp_encrypted_field_storage_help2 "" 627 | destination_parameters.scp_remote_directory "Remote directory for archive upload:" 628 | destination_parameters.scp_cipher "Cipher" 629 | destination_parameters.scp_cipher_help "" 630 | destination_parameters.smb_remote_server "Destination IP:" 631 | destination_parameters.smb_remote_server_help "" 632 | destination_parameters.smb_remote_username "Username:" 633 | destination_parameters.smb_remote_domain "Domain Name:" 634 | destination_parameters.smb_remote_domain_help "" 635 | destination_parameters.smb_remote_password "Password:" 636 | destination_parameters.smb_remote_password_help "" 637 | destination_parameters.smb_remote_password_help2 "" 638 | destination_parameters.smb_remote_path "SMB/CIFS share name:" 639 | destination_parameters.smb_remote_path_help "" 640 | destination_parameters.smb_remote_directory "Target path inside SMB Share:" 641 | destination_parameters.smb_remote_directory_help "" 642 | destination_parameters.smb_local_mountdir "Local mount point:" 643 | destination_parameters.smb_local_mountdir_help "" 644 | destination_parameters.ftp_remote_username "Username:" 645 | destination_parameters.ftp_remote_password "Password:" 646 | destination_parameters.ftp_encrypted_field_storage_help "" 647 | destination_parameters.ftp_remote_server "Destination IP:" 648 | destination_parameters.ftp_remote_directory "Set the remote directory the archive should be copied to:" 649 | destination_parameters.filename_format "Select the filename format:" 650 | destination_parameters.filename_format_help "" 651 | destination_parameters.pruning_enable "Activate automatic pruning?" 652 | destination_parameters.pruning_help "" 653 | destination_parameters.keep_amount "Amount of files to keep at any given time:" 654 | } 655 | } 656 | role-acl { admin manager resource-admin } 657 | run-as none 658 | } 659 | } 660 | description none 661 | ignore-verification false 662 | requires-bigip-version-max none 663 | requires-bigip-version-min 11.5.4 664 | requires-modules { ltm } 665 | signing-key none 666 | tmpl-checksum none 667 | tmpl-signature none 668 | } 669 | -------------------------------------------------------------------------------- /f5.automated_backup.v3.1.1.tmpl: -------------------------------------------------------------------------------- 1 | # iApp VERSIONS (From what I gathered perusing DevCentral) 2 | # ~v2.0 - 20140312 - Initially posted releases (v11.4.0-11.6.x? compatibility). (Developed/posted by Thomas Schockaert) 3 | # v2.1.1 - 20160916 - Retooled SMB upload from smbclient to "mount -t cifs" (v12.1+ compatibility). (Developed/posted by MAG) 4 | # v2.2.1 - 20171214 - Allowed multiple instances of iApp by leveraging $tmsh::app_name to create unique object names. (Developed by Daniel Tavernier/tabernarious) 5 | # v2.2.2 - 20171214 - Added "/" to "mount -t cifs" command and clarified/expanded help for SMB (CIFS) Destination Parameters. (Developed by Daniel Tavernier/tabernarious) 6 | # v2.2.3 - 20171214 - Set many fields to "required" and set reasonable default values to prevent loading/configuration errors. Expanded help regarding private keys. (Developed by Daniel Tavernier/tabernarious) 7 | # v2.2.4 - 20171214 - Added fix to force FTP to use binary upload. (Copied code posted by Roy van Dongen, posted by Daniel Tavernier/tabernarious) 8 | # v2.2.4a - 20171215 - Added items to FUTURE list. 9 | # v2.2.5 - 20171228 - Added notes about special characters in passwords. Added Deployment Information and ConfigSync sections. (Developed by Daniel Tavernier/tabernarious) 10 | # v2.2.5a - 20180117 - Added items to FUTURE list. 11 | # v2.2.5b4 - 20180118 - Moved encrypted values for SMB/CIFS to shell script which eliminates ConfigSync issues. Fixed long-password issue by using "-A" with openssl so that base64 encoded strings are written and read as a single line. (Developed by Daniel Tavernier/tabernarious) 12 | # v2.2.5b4+ - 20180118 - Refining changes to SMB/CIFS and replicating to other remote copy types. (Developed by Daniel Tavernier/tabernarious) 13 | # v3.0.0 - 20180124 - (Developed by Daniel Tavernier/tabernarious) 14 | # - Eliminated ConfigSync issues and removed ConfigSync notes section. (Encrypted values now in $script instead of local file.) 15 | # - Passwords now have no length limits. (Using "-A" with openssl which reads/writes base64 encoded strings as a single line.) 16 | # - Added $script error checking for all remote backup types. (Using 'catch' to prevent tcl errors when $script aborts.) 17 | # - Backup files are cleaned up after $script error due to new error checking. 18 | # - Added logging. (Run logs sent to '/var/log/ltm' via logger command which is compatible with BIG-IP Remote Logging configuration (syslog). Run logs AND errors sent to '/var/tmp/scriptd.out'. Errors may include plain-text passwords which should not be in /var/log/ltm or syslog.) 19 | # - Added custom cipher option for SCP. 20 | # - Added StrictHostKeyChecking=no option. 21 | # - Combined SCP and SFTP because they are both using SCP to perform the remote copy. 22 | # v3.1.0 - 20180201 - (Developed by Daniel Tavernier/tabernarious) 23 | # - Removed "app-service none" from iCall objects. The iCall objects are now created as part of the Application Service (iApp) and are properly cleaned up if the iApp is redeployed or deleted. 24 | # - Reasonably tested on 11.5.4 HF2 (SMB worked fine using "mount -t cifs") and altered requires-bigip-version-min to match. 25 | # - Fixing error regarding "script did not successfully complete: (can't read "::destination_parameters__protocol_enable": no such variable" by encompassing most of the "implementation" in a block that first checks $::backup_schedule__frequency_select for "Disable". 26 | # - Added default value to "filename format". 27 | # - Changed UCS default value for $backup_file_name_extension to ".ucs" and added $fname_noext. 28 | # - Removed old SFTP sections and references (now handled through SCP/SFTP). 29 | # - Adjusted logging: added "sleep 1" to ensure proper logging; added $backup_directory to log message. 30 | # - Adjusted some help messages. 31 | # v3.1.1 - 20180331 - Removed TCL double substitution warnings 32 | # - Fixed duplication of UCS file extension when uploading to FTP 33 | 34 | # KNOWN ISSUES 35 | # - Some tcl warnings when loading configuration. 36 | # - Passwords with special characters may cause tcl or bash errors; a backslash must be entered by the user in front of each special character for proper escaping. 37 | # - F5 TMOS 11.4.1 - 11.5.3 untested and may work. 38 | # - BACKUPFILESCRIPTEXTENSION is not understood and may not be needed. 39 | # - Automatic pruning is not 40 | 41 | #REFERENCES 42 | # Git Repository for f5-automated-backup-iapp ( https://github.com/tabernarious/f5-automated-backup-iapp ) 43 | # F5 iApp Automated Backup ( https://devcentral.f5.com/codeshare/f5-iapp-automated-backup-1114 ) 44 | # F5 Automated Backups - The Right Way ( https://devcentral.f5.com/articles/f5-automated-backups-the-right-way ) 45 | # PASTEBIN f5.automated_backup_v2.0 ( https://pastebin.com/YbDj3eMN ) 46 | # Complete F5 Automated Backup Solution ( https://devcentral.f5.com/codeshare/complete-f5-automated-backup-solution?lc=1 ) 47 | # Complete F5 Automated Backup Solution #2 ( https://devcentral.f5.com/codeshare/complete-f5-automated-backup-solution-2-957 ) 48 | # Automated Backup Solution ( https://devcentral.f5.com/questions/automated-backup-solution ) 49 | # Generate Config Backup ( https://devcentral.f5.com/codeshare?sid=285 ) 50 | # PASTEBIN f5.automated_backup_v3.0.0 ( https://pastebin.com/TENAivwW ) 51 | 52 | cli admin-partitions { 53 | update-partition Common 54 | } 55 | sys application template /Common/f5.automated_backup.v3.1.1 { 56 | actions { 57 | definition { 58 | html-help { 59 | } 60 | implementation { 61 | package require iapp 1.0.0 62 | iapp::template start 63 | 64 | tmsh::cd .. 65 | 66 | ## Backup type handler 67 | set backup_type $::backup_type__backup_type_select 68 | set create_backup_command_append_pass "" 69 | set create_backup_command_append_keys "" 70 | if { $backup_type eq "UCS (User Configuration Set)" } { 71 | set create_backup_command "tmsh::save /sys ucs" 72 | set backup_directory /var/local/ucs 73 | # Backup passphrase usage 74 | if { $::backup_type__backup_passphrase_select eq "Yes" } { 75 | set backup_passphrase $::backup_type__backup_passphrase 76 | set create_backup_command_append_pass "passphrase $backup_passphrase" 77 | } 78 | # Backup private key inclusion 79 | if { $::backup_type__backup_includeprivatekeys eq "No" } { 80 | set create_backup_command_append_keys "no-private-key" 81 | } 82 | set backup_file_name "" 83 | set backup_file_name_extension ".ucs" 84 | set backup_file_script_extension ".ucs" 85 | } 86 | elseif { $backup_type eq "SCF (Single Configuration File)" } { 87 | set create_backup_command "tmsh::save /sys config file" 88 | set backup_directory /var/local/scf 89 | set backup_file_name_extension ".scf" 90 | set backup_file_script_extension ".scf" 91 | } 92 | 93 | set freq $::backup_schedule__frequency_select 94 | 95 | if { $freq != "Disable" } { 96 | # Ensure a default $filename_format is set 97 | if { $::destination_parameters__filename_format eq "" } { 98 | set filename_format {${host}_%Y%m%d_%H%M%S} 99 | } 100 | else { 101 | set filename_format [lindex [split $::destination_parameters__filename_format " "] 0] 102 | } 103 | 104 | if { $::destination_parameters__protocol_enable eq "Remotely via SCP/SFTP" } { 105 | # Get the F5 Master key 106 | set f5masterkey [exec f5mku -K] 107 | # Store the target server information securely, encrypted with the unit key 108 | set encryptedusername [exec echo "$::destination_parameters__scp_remote_username" | openssl aes-256-ecb -salt -a -A -k ${f5masterkey}] 109 | set encryptedserver [exec echo "$::destination_parameters__scp_remote_server" | openssl aes-256-ecb -salt -a -A -k ${f5masterkey}] 110 | set encrypteddirectory [exec echo "$::destination_parameters__scp_remote_directory" | openssl aes-256-ecb -salt -a -A -k ${f5masterkey}] 111 | # Clean the private key data before cleanup 112 | set cleaned_privatekey [exec echo "$::destination_parameters__scp_sshprivatekey" | sed -e "s/BEGIN RSA PRIVATE KEY/BEGIN;RSA;PRIVATE;KEY/g" -e "s/END RSA PRIVATE KEY/END;RSA;PRIVATE;KEY/g" -e "s/ /\\\n/g" -e "s/;/ /g"] 113 | # Encrypt the private key data before dumping to a file 114 | set encrypted_privatekey [exec echo "$cleaned_privatekey" | openssl aes-256-ecb -salt -a -A -k ${f5masterkey}] 115 | # Set optional cipher for SCP (e.g. aes256-gcm@openssh.com) 116 | if { "$::destination_parameters__scp_cipher" equals "" } { 117 | set scp_cipher "" 118 | } else { 119 | set scp_cipher "-c $::destination_parameters__scp_cipher" 120 | } 121 | # Set optional "StrictHostKeyChecking=no" 122 | if { "$::destination_parameters__scp_stricthostkeychecking" equals "Yes" } { 123 | set scp_stricthostkeychecking "-o StrictHostKeyChecking=yes" 124 | } else { 125 | set scp_stricthostkeychecking "-o StrictHostKeyChecking=no" 126 | } 127 | # Create the iCall action 128 | set script { 129 | exec echo "f5.automated_backup iApp TMSHAPPNAME: STARTED" >> /var/tmp/scriptd.out 130 | exec logger -p local0.info "f5.automated_backup iApp TMSHAPPNAME: STARTED" 131 | # Get the hostname of the device we're running on 132 | set host [tmsh::get_field_value [lindex [tmsh::get_config sys global-settings] 0] hostname] 133 | # Get the current date and time in a specific format 134 | set cdate [clock format [clock seconds] -format "FORMAT"] 135 | # Form the filename for the backup 136 | set fname_noext "${cdate}" 137 | set fname "${cdate}BACKUPFILENAMEXTENSION" 138 | # Run the 'create backup' command 139 | exec echo "f5.automated_backup iApp TMSHAPPNAME: $fname GENERATING" >> /var/tmp/scriptd.out 140 | exec logger -p local0.info "f5.automated_backup iApp TMSHAPPNAME: $fname GENERATING" 141 | # Delay 1 second to allow proper logging to /var/tmp/scriptd.out 142 | exec sleep 1 143 | BACKUPCOMMAND $fname BACKUPAPPEND_PASS BACKUPAPPEND_KEYS 144 | exec echo "f5.automated_backup iApp TMSHAPPNAME: $fname SAVED LOCALLY (BACKUPDIRECTORY)" >> /var/tmp/scriptd.out 145 | exec logger -p local0.info "f5.automated_backup iApp TMSHAPPNAME: $fname SAVED LOCALLY (BACKUPDIRECTORY)" 146 | # Set the script filename 147 | set scriptfile "/var/tmp/f5.automated_backup__TMSHAPPNAME_scp.sh" 148 | # Clean, recreate, and run a custom bash script that will perform the SCP upload 149 | exec rm -f $scriptfile 150 | exec echo "yes" 151 | exec echo -e "scp_function()\n{\n\tf5masterkey=\$(f5mku -K)\n\tusername=\$(echo \"ENCRYPTEDUSERNAME\" | openssl aes-256-ecb -salt -a -A -d -k \${f5masterkey})\n\tserver=\$(echo \"ENCRYPTEDSERVER\" | openssl aes-256-ecb -salt -a -A -d -k \${f5masterkey})\n\tdirectory=\$(echo \"ENCRYPTEDDIRECTORY\" | openssl aes-256-ecb -salt -a -A -d -k \${f5masterkey})\n\techo \"ENCRYPTEDPRIVATEKEY\" | openssl aes-256-ecb -salt -a -A -d -k \${f5masterkey} > /var/tmp/TMSHAPPNAME_scp.key\n\n\tchmod 600 /var/tmp/TMSHAPPNAME_scp.key\n\tscp -i /var/tmp/TMSHAPPNAME_scp.key SCPCIPHER SCPSTRICTHOSTKEYCHECKING BACKUPDIRECTORY/${fname_noext}BACKUPFILESCRIPTEXTENSION \${username}@\${server}:\${directory} 2>> /var/tmp/scriptd.out\n\tscp_result=\$?\n\trm -f /var/tmp/TMSHAPPNAME_scp.key\n\treturn \$scp_result\n}\n\nscp_function" > $scriptfile 152 | exec chmod +x $scriptfile 153 | exec echo "f5.automated_backup iApp TMSHAPPNAME: $fname REMOTE COPY (SCP) STARTING" >> /var/tmp/scriptd.out 154 | exec logger -p local0.info "f5.automated_backup iApp TMSHAPPNAME: $fname REMOTE COPY (SCP) STARTING" 155 | if { [catch {exec $scriptfile}] } { 156 | exec echo "f5.automated_backup iApp TMSHAPPNAME: $fname REMOTE COPY (SCP) FAILED (check for errors above)" >> /var/tmp/scriptd.out 157 | exec logger -p local0.crit "f5.automated_backup iApp TMSHAPPNAME: $fname REMOTE COPY (SCP) FAILED (see /var/tmp/scriptd.out for errors)" 158 | } else { 159 | exec echo "f5.automated_backup iApp TMSHAPPNAME: $fname REMOTE COPY (SCP) SUCCEEDED" >> /var/tmp/scriptd.out 160 | exec logger -p local0.notice "f5.automated_backup iApp TMSHAPPNAME: $fname REMOTE COPY (SCP) SUCCEEDED" 161 | } 162 | # Clean up local files 163 | exec rm -f $scriptfile 164 | exec rm -f /var/tmp/TMSHAPPNAME_scp.key 165 | exec rm -f BACKUPDIRECTORY/${fname_noext}BACKUPFILESCRIPTEXTENSION 166 | exec echo "f5.automated_backup iApp TMSHAPPNAME: FINISHED" >> /var/tmp/scriptd.out 167 | exec logger -p local0.info "f5.automated_backup iApp TMSHAPPNAME: FINISHED" 168 | } 169 | # Swap many variables into $script; due to the curly braces used to initially set $script, any referenced variables will *not* be expanded simply by deploying the iApp. 170 | set script [string map [list FORMAT $filename_format BACKUPFILENAMEXTENSION $backup_file_name_extension BACKUPFILESCRIPTEXTENSION $backup_file_script_extension BACKUPDIRECTORY $backup_directory BACKUPCOMMAND $create_backup_command BACKUPAPPEND_PASS $create_backup_command_append_pass BACKUPAPPEND_KEYS $create_backup_command_append_keys TMSHAPPNAME $tmsh::app_name ENCRYPTEDUSERNAME $encryptedusername ENCRYPTEDSERVER $encryptedserver ENCRYPTEDDIRECTORY $encrypteddirectory ENCRYPTEDPRIVATEKEY $encrypted_privatekey SCPCIPHER $scp_cipher SCPSTRICTHOSTKEYCHECKING $scp_stricthostkeychecking] $script] 171 | } 172 | elseif { $::destination_parameters__protocol_enable eq "Remotely via FTP" } { 173 | # Get the F5 Master key 174 | set f5masterkey [exec f5mku -K] 175 | # Store the target server information securely, encrypted with the unit key 176 | set encryptedusername [exec echo "$::destination_parameters__ftp_remote_username" | openssl aes-256-ecb -salt -a -A -k ${f5masterkey}] 177 | set encryptedpassword [exec echo "$::destination_parameters__ftp_remote_password" | openssl aes-256-ecb -salt -a -A -k ${f5masterkey}] 178 | set encryptedserver [exec echo "$::destination_parameters__ftp_remote_server" | openssl aes-256-ecb -salt -a -A -k ${f5masterkey}] 179 | set encrypteddirectory [exec echo "$::destination_parameters__ftp_remote_directory" | openssl aes-256-ecb -salt -a -A -k ${f5masterkey}] 180 | # Create the iCall action 181 | set script { 182 | exec echo "f5.automated_backup iApp TMSHAPPNAME: STARTED" >> /var/tmp/scriptd.out 183 | exec logger -p local0.info "f5.automated_backup iApp TMSHAPPNAME: STARTED" 184 | # Get the hostname of the device we're running on 185 | set host [tmsh::get_field_value [lindex [tmsh::get_config sys global-settings] 0] hostname] 186 | # Get the current date and time in a specific format 187 | set cdate [clock format [clock seconds] -format "FORMAT"] 188 | # Form the filename for the backup 189 | set fname_noext "${cdate}" 190 | set fname "${cdate}BACKUPFILENAMEXTENSION" 191 | # Run the 'create backup' command 192 | exec echo "f5.automated_backup iApp TMSHAPPNAME: $fname GENERATING" >> /var/tmp/scriptd.out 193 | exec logger -p local0.info "f5.automated_backup iApp TMSHAPPNAME: $fname GENERATING" 194 | # Delay 1 second to allow proper logging to /var/tmp/scriptd.out 195 | exec sleep 1 196 | BACKUPCOMMAND $fname BACKUPAPPEND_PASS BACKUPAPPEND_KEYS 197 | exec echo "f5.automated_backup iApp TMSHAPPNAME: $fname SAVED LOCALLY (BACKUPDIRECTORY)" >> /var/tmp/scriptd.out 198 | exec logger -p local0.info "f5.automated_backup iApp TMSHAPPNAME: $fname SAVED LOCALLY (BACKUPDIRECTORY)" 199 | # Set the config file 200 | set configfile "/config/f5.automated_backup__TMSHAPPNAME_ftp.conf" 201 | # Set the script filename 202 | set scriptfile "/var/tmp/f5.automated_backup__TMSHAPPNAME_ftp.sh" 203 | # Clean, recreate, run and reclean a custom bash script that will perform the FTP upload 204 | exec rm -f $scriptfile 205 | # Updated command v2.2.4 to force binary transfer. 206 | exec echo -e "ftp_function()\n{\n\tf5masterkey=\$(f5mku -K)\n\tusername=\$(echo \"ENCRYPTEDUSERNAME\" | openssl aes-256-ecb -salt -a -A -d -k \${f5masterkey})\n\tpassword=\$(echo \"ENCRYPTEDPASSWORD\" | openssl aes-256-ecb -salt -a -A -d -k \${f5masterkey})\n\tserver=\$(echo \"ENCRYPTEDSERVER\" | openssl aes-256-ecb -salt -a -A -d -k \${f5masterkey})\n\tdirectory=\$(echo \"ENCRYPTEDDIRECTORY\" | openssl aes-256-ecb -salt -a -A -d -k \${f5masterkey})\n\n\tftp_return=\$(ftp -n \${server} << END_FTP\nquote USER \${username}\nquote PASS \${password}\nbinary\nput BACKUPDIRECTORY/${fname_noext}BACKUPFILESCRIPTEXTENSION \${directory}/${fname_noext}BACKUPFILESCRIPTEXTENSION\nquit\nEND_FTP\n)\n\tif \[ \"\$ftp_return\" == \"\" \]\n\tthen\n\t\treturn 0\n\telse\n\t\techo \"\$ftp_return\" >> /var/tmp/scriptd.out\n\t\treturn 1\n\tfi\n}\n\nftp_function" > $scriptfile 207 | exec chmod +x $scriptfile 208 | exec echo "f5.automated_backup iApp TMSHAPPNAME: $fname REMOTE COPY (FTP) STARTING" >> /var/tmp/scriptd.out 209 | exec logger -p local0.info "f5.automated_backup iApp TMSHAPPNAME: $fname REMOTE COPY (FTP) STARTING" 210 | if { [catch {exec $scriptfile}] } { 211 | exec echo "f5.automated_backup iApp TMSHAPPNAME: $fname REMOTE COPY (FTP) FAILED (check for errors above)" >> /var/tmp/scriptd.out 212 | exec logger -p local0.crit "f5.automated_backup iApp TMSHAPPNAME: $fname REMOTE COPY (FTP) FAILED (see /var/tmp/scriptd.out for errors)" 213 | } else { 214 | exec echo "f5.automated_backup iApp TMSHAPPNAME: $fname REMOTE COPY (FTP) SUCCEEDED" >> /var/tmp/scriptd.out 215 | exec logger -p local0.notice "f5.automated_backup iApp TMSHAPPNAME: $fname REMOTE COPY (FTP) SUCCEEDED" 216 | } 217 | # Clean up local files 218 | exec rm -f $scriptfile 219 | exec rm -f BACKUPDIRECTORY/${fname_noext}BACKUPFILESCRIPTEXTENSION 220 | exec echo "f5.automated_backup iApp TMSHAPPNAME: FINISHED" >> /var/tmp/scriptd.out 221 | exec logger -p local0.info "f5.automated_backup iApp TMSHAPPNAME: FINISHED" 222 | } 223 | # Swap many variables into $script; due to the curly braces used to initially set $script, any referenced variables will *not* be expanded simply by deploying the iApp. 224 | set script [string map [list FORMAT $filename_format BACKUPFILENAMEXTENSION $backup_file_name_extension BACKUPFILESCRIPTEXTENSION $backup_file_script_extension BACKUPDIRECTORY $backup_directory BACKUPCOMMAND $create_backup_command BACKUPAPPEND_PASS $create_backup_command_append_pass BACKUPAPPEND_KEYS $create_backup_command_append_keys TMSHAPPNAME $tmsh::app_name ENCRYPTEDUSERNAME $encryptedusername ENCRYPTEDPASSWORD $encryptedpassword ENCRYPTEDSERVER $encryptedserver ENCRYPTEDDIRECTORY $encrypteddirectory] $script] 225 | } 226 | elseif { $::destination_parameters__protocol_enable eq "Remotely via SMB/CIFS" } { 227 | # Get the F5 Master key 228 | set f5masterkey [exec f5mku -K] 229 | # Store the target server information securely, encrypted with the unit key 230 | set encryptedusername [exec echo "$::destination_parameters__smb_remote_username" | openssl aes-256-ecb -salt -a -A -k ${f5masterkey}] 231 | set encryptedpassword [exec echo "$::destination_parameters__smb_remote_password" | openssl aes-256-ecb -salt -a -A -k ${f5masterkey}] 232 | set encryptedmsdomain [exec echo "$::destination_parameters__smb_remote_domain" | openssl aes-256-ecb -salt -a -A -k ${f5masterkey}] 233 | set encryptedserver [exec echo "$::destination_parameters__smb_remote_server" | openssl aes-256-ecb -salt -a -A -k ${f5masterkey}] 234 | set encryptedmsshare [exec echo "$::destination_parameters__smb_remote_path" | openssl aes-256-ecb -salt -a -A -k ${f5masterkey}] 235 | set encryptedmssubdir [exec echo "$::destination_parameters__smb_remote_directory" | openssl aes-256-ecb -salt -a -A -k ${f5masterkey}] 236 | set encryptedmountp [exec echo "$::destination_parameters__smb_local_mountdir" | openssl aes-256-ecb -salt -a -A -k ${f5masterkey}] 237 | # Create the iCall action 238 | set script { 239 | exec echo "f5.automated_backup iApp TMSHAPPNAME: STARTED" >> /var/tmp/scriptd.out 240 | exec logger -p local0.info "f5.automated_backup iApp TMSHAPPNAME: STARTED" 241 | # Get the hostname of the device we're running on 242 | set host [tmsh::get_field_value [lindex [tmsh::get_config sys global-settings] 0] hostname] 243 | # Get the current date and time in a specific format 244 | set cdate [clock format [clock seconds] -format "FORMAT"] 245 | # Form the filename for the backup 246 | set fname_noext "${cdate}" 247 | set fname "${cdate}BACKUPFILENAMEXTENSION" 248 | # Run the 'create backup' command 249 | exec echo "f5.automated_backup iApp TMSHAPPNAME: $fname GENERATING" >> /var/tmp/scriptd.out 250 | exec logger -p local0.info "f5.automated_backup iApp TMSHAPPNAME: $fname GENERATING" 251 | # Delay 1 second to allow proper logging to /var/tmp/scriptd.out 252 | exec sleep 1 253 | BACKUPCOMMAND $fname BACKUPAPPEND_PASS BACKUPAPPEND_KEYS 254 | exec echo "f5.automated_backup iApp TMSHAPPNAME: $fname SAVED LOCALLY (BACKUPDIRECTORY)" >> /var/tmp/scriptd.out 255 | exec logger -p local0.info "f5.automated_backup iApp TMSHAPPNAME: $fname SAVED LOCALLY (BACKUPDIRECTORY)" 256 | # Set the script filename 257 | set scriptfile "/var/tmp/f5.automated_backup__TMSHAPPNAME_smb.sh" 258 | # Clean, recreate, run and reclean a custom bash script that will perform the SMB upload 259 | exec rm -f $scriptfile 260 | exec echo -e "\#\!/bin/sh\nf5masterkey=\$(f5mku -K)\nusername=\$(echo \"ENCRYPTEDUSERNAME\" | openssl aes-256-ecb -salt -a -A -d -k \${f5masterkey})\npassword=\$(echo \"ENCRYPTEDPASSWORD\" | openssl aes-256-ecb -salt -a -A -d -k \${f5masterkey})\nmsdomain=\$(echo \"ENCRYPTEDMSDOMAIN\" | openssl aes-256-ecb -salt -a -A -d -k \${f5masterkey})\nserver=\$(echo \"ENCRYPTEDSERVER\" | openssl aes-256-ecb -salt -a -A -d -k \${f5masterkey})\nmsshare=\$(echo \"ENCRYPTEDMSSHARE\" | openssl aes-256-ecb -salt -a -A -d -k \${f5masterkey})\nmssubdir=\$(echo \"ENCRYPTEDMSSUBDIR\" | openssl aes-256-ecb -salt -a -A -d -k \${f5masterkey})\nmountp=\$(echo \"ENCRYPTEDMOUNTP\" | openssl aes-256-ecb -salt -a -A -d -k \${f5masterkey})\ncd /var/local/ucs\nif \[ \! -d \${mountp} \]\nthen\n\tmkdir -p \${mountp}\n\tif \[ \$? -ne 0 \]\n\tthen\n\t\trm -f ${fname_noext}BACKUPFILESCRIPTEXTENSION\n\t\texit 1\n\tfi\nfi\nmount -t cifs //\${server}/\${msshare} \${mountp} -o user=\${username}%\${password},domain=\${msdomain} 2>> /var/tmp/scriptd.out\nif \[ \$? -ne 0 \]\n\tthen\n\trm -f ${fname_noext}BACKUPFILESCRIPTEXTENSION\n\texit 1\nfi\nfONSMB=\$(ls -t \${mountp}\${mssubdir}/\*.ucs 2>/dev/null| head -n 1 2>/dev/null)\nif \[ \"X\"\${fONSMB} \!= \"X\" \]\n\tthen\n\tsum1=\$(md5sum ${fname_noext}BACKUPFILESCRIPTEXTENSION | awk '{print \$1}')\n\tsum2=\$(md5sum \${fONSMB} | awk \'{print \$1}\')\n\tif \[ \${sum1} == \${sum2} \]\n\tthen\n\t\techo \"ERROR: File ${fname_noext}BACKUPFILESCRIPTEXTENSION already exists in //\${server}/\${msshare}/\${mssubdir}\" >> /var/tmp/scriptd.out\n\t\tumount \${mountp}\n\t\trm -f ${fname_noext}BACKUPFILESCRIPTEXTENSION\n\t\texit 1\n\tfi\nfi\ncp ${fname_noext}BACKUPFILESCRIPTEXTENSION \${mountp}\${mssubdir}\nrm -f ${fname_noext}BACKUPFILESCRIPTEXTENSION\numount \${mountp}\n\nexit 0\n\n" > $scriptfile 261 | exec chmod +x $scriptfile 262 | exec echo "f5.automated_backup iApp TMSHAPPNAME: $fname STARTING REMOTE COPY (SMB/CIFS)" >> /var/tmp/scriptd.out 263 | exec logger -p local0.info "f5.automated_backup iApp TMSHAPPNAME: $fname REMOTE COPY (SMB/CIFS) STARTING" 264 | if { [catch {exec $scriptfile}] } { 265 | exec echo "f5.automated_backup iApp TMSHAPPNAME: $fname REMOTE COPY (SMB/CIFS) FAILED (check for errors above)" >> /var/tmp/scriptd.out 266 | exec logger -p local0.crit "f5.automated_backup iApp TMSHAPPNAME: $fname REMOTE COPY (SMB/CIFS) FAILED (see /var/tmp/scriptd.out for errors)" 267 | } else { 268 | exec echo "f5.automated_backup iApp TMSHAPPNAME: $fname REMOTE COPY (SMB/CIFS) SUCCEEDED" >> /var/tmp/scriptd.out 269 | exec logger -p local0.notice "f5.automated_backup iApp TMSHAPPNAME: $fname REMOTE COPY (SMB/CIFS) SUCCEEDED" 270 | } 271 | # Clean up local files 272 | exec rm -f $scriptfile 273 | exec rm -f BACKUPDIRECTORY/${fname_noext}BACKUPFILESCRIPTEXTENSION 274 | exec echo "f5.automated_backup iApp TMSHAPPNAME: FINISHED" >> /var/tmp/scriptd.out 275 | exec logger -p local0.info "f5.automated_backup iApp TMSHAPPNAME: FINISHED" 276 | } 277 | # Swap many variables into $script; due to the curly braces used to initially set $script, any referenced variables will *not* be expanded simply by deploying the iApp. 278 | set script [string map [list FORMAT $filename_format BACKUPFILENAMEXTENSION $backup_file_name_extension BACKUPFILESCRIPTEXTENSION $backup_file_script_extension BACKUPDIRECTORY $backup_directory BACKUPCOMMAND $create_backup_command BACKUPAPPEND_PASS $create_backup_command_append_pass BACKUPAPPEND_KEYS $create_backup_command_append_keys TMSHAPPNAME $tmsh::app_name ENCRYPTEDUSERNAME $encryptedusername ENCRYPTEDPASSWORD $encryptedpassword ENCRYPTEDMSDOMAIN $encryptedmsdomain ENCRYPTEDSERVER $encryptedserver ENCRYPTEDMSSHARE $encryptedmsshare ENCRYPTEDMSSUBDIR $encryptedmssubdir ENCRYPTEDMOUNTP $encryptedmountp] $script] 279 | } 280 | else { 281 | set script { 282 | exec echo "f5.automated_backup iApp TMSHAPPNAME: STARTED" >> /var/tmp/scriptd.out 283 | exec logger -p local0.info "f5.automated_backup iApp TMSHAPPNAME: STARTED" 284 | # Get the hostname of the device we're running on 285 | set host [tmsh::get_field_value [lindex [tmsh::get_config sys global-settings] 0] hostname] 286 | # Get the current date and time in a specific format 287 | set cdate [clock format [clock seconds] -format "FORMAT"] 288 | # Form the filename for the backup 289 | set fname "${cdate}BACKUPFILENAMEXTENSION" 290 | # Run the 'create backup' command 291 | exec echo "f5.automated_backup iApp TMSHAPPNAME: $fname GENERATING" >> /var/tmp/scriptd.out 292 | exec logger -p local0.info "f5.automated_backup iApp TMSHAPPNAME: $fname GENERATING" 293 | # Delay 1 second to allow proper logging to /var/tmp/scriptd.out 294 | exec sleep 1 295 | BACKUPCOMMAND $fname BACKUPAPPEND_PASS BACKUPAPPEND_KEYS 296 | exec echo "f5.automated_backup iApp TMSHAPPNAME: $fname SAVED LOCALLY (BACKUPDIRECTORY)" >> /var/tmp/scriptd.out 297 | exec logger -p local0.info "f5.automated_backup iApp TMSHAPPNAME: $fname SAVED LOCALLY (BACKUPDIRECTORY)" 298 | exec echo "f5.automated_backup iApp TMSHAPPNAME: FINISHED" >> /var/tmp/scriptd.out 299 | exec logger -p local0.info "f5.automated_backup iApp TMSHAPPNAME: FINISHED" 300 | } 301 | # Swap many variables into $script; due to the curly braces used to initially set $script, any referenced variables will *not* be expanded simply by deploying the iApp. 302 | set script [string map [list FORMAT $filename_format BACKUPFILENAMEXTENSION $backup_file_name_extension BACKUPFILESCRIPTEXTENSION $backup_file_script_extension BACKUPDIRECTORY $backup_directory BACKUPCOMMAND $create_backup_command BACKUPAPPEND_PASS $create_backup_command_append_pass BACKUPAPPEND_KEYS $create_backup_command_append_keys TMSHAPPNAME $tmsh::app_name] $script] 303 | } 304 | 305 | iapp::conf create sys icall script f5.automated_backup__${tmsh::app_name} definition \{ $script \} 306 | 307 | ## Get time info for setting first-occurrence on daily handler from iApp input 308 | #Create the handlers 309 | if { $freq eq "Every X Minutes" } { 310 | set everyxminutes $::backup_schedule__everyxminutes_value 311 | set interval [expr {$everyxminutes*60}] 312 | set cdate [clock format [clock seconds] -format "%Y-%m-%d:%H:%M"] 313 | iapp::conf create sys icall handler periodic f5.automated_backup__${tmsh::app_name}-handler \{ \ 314 | interval $interval \ 315 | first-occurrence $cdate:00 \ 316 | script f5.automated_backup__${tmsh::app_name} \} 317 | } 318 | elseif { $freq eq "Every X Hours" } { 319 | set everyxhours $::backup_schedule__everyxhours_value 320 | set interval [expr {$everyxhours*3600}] 321 | set minutes $::backup_schedule__everyxhours_min_select 322 | set cdate [clock format [clock seconds] -format "%Y-%m-%d:%H"] 323 | iapp::conf create sys icall handler periodic f5.automated_backup__${tmsh::app_name}-handler \{ \ 324 | interval $interval \ 325 | first-occurrence $cdate:$minutes:00 \ 326 | script f5.automated_backup__${tmsh::app_name} \} 327 | } 328 | elseif { $freq eq "Every X Days" } { 329 | set everyxdays $::backup_schedule__everyxdays_value 330 | set interval [expr {$everyxdays*86400}] 331 | set hours [lindex [split $::backup_schedule__everyxdays_time ":"] 0] 332 | set minutes [lindex [split $::backup_schedule__everyxdays_time ":"] 1] 333 | set cdate [clock format [clock seconds] -format "%Y-%m-%d"] 334 | iapp::conf create sys icall handler periodic f5.automated_backup__${tmsh::app_name}-handler \{ \ 335 | interval $interval \ 336 | first-occurrence $cdate:$hours:$minutes:00 \ 337 | script f5.automated_backup__${tmsh::app_name} \} 338 | } 339 | elseif { $freq eq "Every X Weeks" } { 340 | set everyxweeks $::backup_schedule__everyxweeks_value 341 | set interval [expr {$everyxweeks*604800}] 342 | set hours [lindex [split $::backup_schedule__everyxweeks_time ":"] 0] 343 | set minutes [lindex [split $::backup_schedule__everyxweeks_time ":"] 1] 344 | ## Get day of week info for setting first-occurrence on weekly handler from iApp input 345 | array set dowmap { 346 | Sunday 0 347 | Monday 1 348 | Tuesday 2 349 | Wednesday 3 350 | Thursday 4 351 | Friday 5 352 | Saturday 6 353 | } 354 | set sday_name $::backup_schedule__everyxweeks_dow_select 355 | set sday_num $dowmap($sday_name) 356 | set cday_name [clock format [clock seconds] -format "%A"] 357 | set cday_num $dowmap($cday_name) 358 | set date_offset [expr {86400*($sday_num - $cday_num)}] 359 | set date_final [clock format [expr {[clock seconds] + $date_offset}] -format "%Y-%m-%d"] 360 | iapp::conf create sys icall handler periodic f5.automated_backup__${tmsh::app_name}-handler \{ \ 361 | interval $interval \ 362 | first-occurrence $date_final:$hours:$minutes:00 \ 363 | script f5.automated_backup__${tmsh::app_name} \} 364 | } 365 | elseif { $freq eq "Every X Months" } { 366 | set everyxmonths $::backup_schedule__everyxmonths_value 367 | set interval [expr {60*60*24*365}] 368 | set dom $::backup_schedule__everyxmonths_dom_select 369 | set hours [lindex [split $::backup_schedule__everyxmonths_time ":"] 0] 370 | set minutes [lindex [split $::backup_schedule__everyxmonths_time ":"] 1] 371 | for { set month 1 } { $month < 13 } { set month [expr {$month+$everyxmonths}] } { 372 | set cdate [clock format [clock seconds] -format "%Y-$month-$dom"] 373 | iapp::conf create sys icall handler periodic f5.automated_backup__${tmsh::app_name}-month_${month}-handler \{ \ 374 | interval $interval \ 375 | first-occurrence $cdate:$hours:$minutes:00 \ 376 | script f5.automated_backup__${tmsh::app_name} \} 377 | } 378 | } 379 | elseif { $freq eq "Custom" } { 380 | set hours [lindex [split $::backup_schedule__custom_time ":"] 0] 381 | set minutes [lindex [split $::backup_schedule__custom_time ":"] 1] 382 | ## Get day of week info for setting first-occurrence on weekly handler from iApp input 383 | array set dowmap { 384 | Sunday 0 385 | Monday 1 386 | Tuesday 2 387 | Wednesday 3 388 | Thursday 4 389 | Friday 5 390 | Saturday 6 391 | } 392 | foreach sday_name $::backup_schedule__custom_dow_select { 393 | set sday_num $dowmap($sday_name) 394 | set cday_name [clock format [clock seconds] -format "%A"] 395 | set cday_num $dowmap($cday_name) 396 | set date_offset [expr {86400*($sday_num - $cday_num)}] 397 | set date_final [clock format [expr {[clock seconds] + $date_offset}] -format "%Y-%m-%d"] 398 | iapp::conf create sys icall handler periodic f5.automated_backup__${tmsh::app_name}-handler-$sday_name \{ \ 399 | interval 604800 \ 400 | first-occurrence $date_final:$hours:$minutes:00 \ 401 | script f5.automated_backup__${tmsh::app_name} \} 402 | } 403 | } 404 | else { 405 | 406 | } 407 | 408 | ## Automatic Pruning handler 409 | if { $::destination_parameters__protocol_enable eq "On this F5" } { 410 | set autoprune $::destination_parameters__pruning_enable 411 | if { $autoprune eq "Yes" } { 412 | set prune_conserve $::destination_parameters__keep_amount 413 | set today [clock format [clock seconds] -format "%Y-%m-%d"] 414 | set script { 415 | # Get the hostname of the device we're running on 416 | set host [tmsh::get_field_value [lindex [tmsh::get_config sys global-settings] 0] hostname] 417 | # Set the script filename 418 | set scriptfile "/var/tmp/autopruning.sh" 419 | # Clean, recreate, run and reclean a custom bash script that will perform the pruning 420 | exec rm -f $scriptfile 421 | exec echo -e "files_tokeep=\$(ls -t /var/local/ucs/*.ucs | head -n CONSERVE\)\nfor current_ucs_file in `ls /var/local/ucs/*.ucs` ; do\n\tcurrent_ucs_file_basename=`basename \$current_ucs_file`\n\tcheck_file=\$(echo \$files_tokeep | grep -w \$current_ucs_file_basename)\n\tif \[ \"\$check_file\" == \"\" \] ; then\n\t\trm -f \$current_ucs_file\n\tfi\ndone" > $scriptfile 422 | exec chmod +x $scriptfile 423 | exec $scriptfile 424 | exec rm -f $scriptfile 425 | } 426 | set script [string map [list CONSERVE $prune_conserve] $script] 427 | iapp::conf create sys icall script f5.automated_backup__${tmsh::app_name}_pruning definition \{ $script \} 428 | set cdate [clock format [clock seconds] -format "%Y-%m-%d:%H:%M"] 429 | # Interval can be increased as needed if pruning every minute is problematic 430 | iapp::conf create sys icall handler periodic f5.automated_backup__${tmsh::app_name}_pruning-handler \{ \ 431 | interval 60 \ 432 | first-occurrence $cdate:00 \ 433 | script f5.automated_backup__${tmsh::app_name}_pruning \} 434 | } 435 | } 436 | } 437 | 438 | iapp::template end 439 | } 440 | macro { 441 | } 442 | presentation { 443 | section deployment_info { 444 | message deployment_info_first_time "Deploying the iApp may not trigger an immediate backup." 445 | message deployment_info_updates "For testing, to force the iApp to run an immediate backup it is easiest to set the Backup Schedule to 'Every X Minutes' and simply change value of 'X equals. Redeploying the iApp will not trigger an immediate backup unless the iCall handler is recreated and the first-occurrence value is set to a time before the moment of redeployment. When testing is complete, set the Backup Schedule to the desired ongoing schedule." 446 | message deployment_info_logs "The general log for all iApps is '/var/tmp/scriptd.out'. This iApp adds run logs and errors to '/var/tmp/scriptd.out'. Additionally, this iApp sends run logs (not full error messages) to '/var/log/ltm' (compatible with BIG-IP Remote Logging configuration)." 447 | } 448 | section backup_type { 449 | choice backup_type_select display "xlarge" { "UCS (User Configuration Set)", "SCF (Single Configuration File)" } 450 | optional ( backup_type_select == "SCF (Single Configuration File)" ) { 451 | message backup_help_scf "WARNING: Beware of choosing SCF file as not all configuration is included therein. Please check out SOL13408 (http://support.f5.com/kb/en-us/solutions/public/13000/400/sol13408.html) for more information." 452 | } 453 | optional ( backup_type_select == "UCS (User Configuration Set)" ) { 454 | choice backup_passphrase_select display "small" { "Yes", "No" } 455 | optional ( backup_passphrase_select == "Yes" ) { 456 | message backup_help_passphrase "WARNING: Losing the passphase will render the archives unusable. The encrypted UCS archive will be a PGP encoded file, *not* simply a tar.gz with a password on it." 457 | password backup_passphrase required display "large" 458 | } 459 | choice backup_includeprivatekeys display "small" { "Yes", "No" } 460 | optional ( backup_includeprivatekeys == "No" ) { 461 | message backup_help_privatekeys "WARNING: A UCS archive that does not contain the private keys CANNOT be used for restoring the device. It should be used for transfers to external services to whom you do not wish to disclose the private keys." 462 | } 463 | } 464 | } 465 | section backup_schedule { 466 | choice frequency_select display "large" { "Disable", "Every X Minutes", "Every X Hours", "Every X Days", "Every X Weeks", "Every X Months", "Custom" } 467 | optional ( frequency_select == "Every X Minutes" ) { 468 | editchoice everyxminutes_value default "30" display "small" { "1", "2", "5", "10", "15", "20", "30", "45", "60" } 469 | } 470 | optional ( frequency_select == "Every X Hours" ) { 471 | editchoice everyxhours_value default "1" display "small" { "1", "2", "3", "4", "6", "12", "24" } 472 | choice everyxhours_min_select display "small" tcl { 473 | for { set x 0 } { $x < 60 } { incr x } { 474 | append mins "$x\n" 475 | } 476 | return $mins 477 | } 478 | } 479 | optional ( frequency_select == "Every X Days" ) { 480 | editchoice everyxdays_value default "1" display "small" { "1", "2", "3", "4", "5", "7", "14" } 481 | string everyxdays_time required display "medium" 482 | } 483 | optional ( frequency_select == "Every X Weeks" ) { 484 | editchoice everyxweeks_value default "1" display "small" { "1", "2", "3", "4", "5", "7", "14" } 485 | choice everyxweeks_dow_select default "Sunday" display "medium" { "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday" } 486 | string everyxweeks_time required display "small" 487 | } 488 | optional ( frequency_select == "Every X Months" ) { 489 | editchoice everyxmonths_value default "1" display "small" { "1", "2", "3", "6", "12" } 490 | choice everyxmonths_dom_select display "small" tcl { 491 | for { set x 1 } { $x < 31 } { incr x } { 492 | append days "$x\n" 493 | } 494 | return $days 495 | } 496 | string everyxmonths_time required display "small" 497 | } 498 | optional ( frequency_select == "Custom" ) { 499 | multichoice custom_dow_select default {"Sunday"} display "medium" { "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday" } 500 | string custom_time required display "small" 501 | } 502 | } 503 | optional ( backup_schedule.frequency_select != "Disable" ) { 504 | section destination_parameters { 505 | choice protocol_enable display "xlarge" { "On this F5", "Remotely via SCP/SFTP", "Remotely via SMB/CIFS", "Remotely via FTP" } 506 | optional ( protocol_enable == "Remotely via SCP/SFTP") { 507 | message scp_sftp_help "A connection to an SSH server can be establish using both SCP and SFTP. SCP is more efficient for copying files to a remote network destination while, for interactive sessions, the SFTP protocol offers more features. This iApp uses SCP." 508 | string scp_remote_server required display "medium" validator "IpAddress" 509 | message scp_remote_server_help "IMPORTANT: Check '/root/.ssh/known_hosts' on each BIG-IP (including HA peers) to ensure the Destination IP above is listed. On each BIG-IP that does not list the Destination IP, connect directly to the Destination IP using the scp or ssh command. You will be asked to verify the 'RSA key fingerprint'. Entering 'yes' will store the fingerprint in '/root/.ssh/known_hosts' and allow subsequent connections without further verification. If IP from the CLI on all BIG-IPs (including HA peers) and verify/accept the fingerprint which should add an entry to the known_hosts file." 510 | choice scp_stricthostkeychecking default "Yes" display "large" { "Yes", "No (INSECURE)" } 511 | optional ( scp_stricthostkeychecking == "No (INSECURE)" ) { 512 | message scp_stricthostkeychecking_warning1 "WARNING: Selecting 'No (INSECURE)' will ignore certificate verification for connections this iApp makes to the server configured above. Backups could be copied to an unintended server, including one owned by a bad actor." 513 | } 514 | message scp_stricthostkeychecking_help1 "It is MOST SECURE to select Yes, which is the SCP/SSH default setting and which will not allow connections to unknown servers. A server is considered 'unknown' until an SSH key fingerprint has been verified, or if the destination SSL certificate changes and the fingerprint no longer matches." 515 | optional ( scp_stricthostkeychecking == "Yes" ) { 516 | message scp_stricthostkeychecking_help2 "Selecting 'No (INSECURE)' will ignore certificate verification for connections this iApp makes to the server configured above." 517 | message scp_stricthostkeychecking_trouble1 "TROUBLESHOOTING: If the SCP script fails with a 'Host key verification failed' or 'No RSA host key is known for' error (which can viewed in /var/tmp/scriptd.out after deploying this iApp), review the IMPORTANT steps (under Destination IP) above regarding the known_hosts file to resolve the issue. Also, review additional troubleshooting notes." 518 | message scp_stricthostkeychecking_trouble2 "TROUBLESHOOTING: If the SCP script fails with a 'WARNING: REMOTE HOST IDENTIFICATION HAS CHANGED!' error (which can viewed in /var/tmp/scriptd.out after deploying this iApp), the certificate on the destination server has changed. This could mean 1) The certificate was updated legitimately, or 2) There is an IP conflict and the script is connecting to the wrong server, or 3) the destination server was replaced or rebuilt and has a new certificate, or 4) a bad actor is intercepting the connection (man-in-the-middle) and the script is rightly warning you to not connect. Investigate the destination server before proceeding." 519 | } 520 | string scp_remote_username required display "medium" 521 | password scp_sshprivatekey required display "large" 522 | message scp_encrypted_field_storage_help "Private key must be non-encrypted and in 'OpenSSH' base64 format. As an example run 'ssh-keygen -t -b 2048 -o -a 100' from the CLI, step through the questions, and view the resulting private key (by default ssh-keygen will save the key to ~/.ssh/id_rsa)." 523 | message scp_encrypted_field_storage_help2 "Passwords and private keys are stored in an encrypted format. The salt for the encryption algorithm is the F5 cluster's Master Key. The master key is not shared when exporting a qkview or UCS, thus rendering your passwords and private keys safe if a backup file were to be stored off-box." 524 | editchoice scp_cipher display "xlarge" { "aes128-ctr", "aes192-ctr", "aes256-ctr", "aes128-gcm@openssh.com", "chacha20-poly1305@openssh.com" } 525 | message scp_cipher_help "Depending on the version of F5 TMOS and the ssh configuration of the destination server, there may be no matching ciphers resulting in a 'no matching cipher found' error (which can viewed in /var/tmp/scriptd.out after deploying this iApp or it can be tested/demonstrated by attempting an scp or ssh connection from this device to the destination server). Find the word 'server' in the error and note the ciphers listed; select one of these ciphers from the list above or paste in one not listed." 526 | string scp_remote_directory display "medium" 527 | } 528 | optional ( protocol_enable == "Remotely via SMB/CIFS") { 529 | string smb_remote_server required display "medium" validator "IpAddress" 530 | message smb_remote_server_help "Ensure this Destination IP is reachable on port 139." 531 | string smb_remote_domain required display "medium" 532 | message smb_remote_domain_help "Start by entering the NetBIOS/Pre-Windows 2000 domain name; the fully qualified DNS domain name may work or be required in some environments." 533 | string smb_remote_username required display "medium" 534 | password smb_remote_password display "medium" 535 | message smb_remote_password_help "Special characters within passwords must be escaped (add a backslash before each special character as you input the password)." 536 | message smb_remote_password_help2 "Passwords and private keys are stored in an encrypted format. The salt for the encryption algorithm is the F5 cluster's Master Key. The master key is not shared when exporting a qkview or UCS, thus rendering your passwords and private keys safe if a backup file were to be stored off-box." 537 | string smb_remote_path required display "medium" 538 | message smb_remote_path_help "SMB share on a remote server. Do not include leading and trailing slashes. If the full share path is //SERVER/SHARE, enter SHARE in this field. If the full share path is //SERVER/PATH/SHARE, enter PATH/SHARE in this field." 539 | string smb_remote_directory display "medium" 540 | message smb_remote_directory_help "Relative path inside the SMB share to copy the file. Leave this field empty to store in root of SMB share. Include one leading slash and no trailing slashes. If the target directory is //SERVER/SHARE/PATH/DIRECTORY, enter /PATH/DIRECTORY in this field." 541 | string smb_local_mountdir required default "/var/tmp/cifs" display "medium" 542 | message smb_local_mountdir_help "Read-Write path on local F5 where SMB share will be mounted. Include one leading slash and no trailing slashes, for example /var/tmp/cifs" 543 | } 544 | optional ( protocol_enable == "Remotely via FTP") { 545 | string ftp_remote_server required display "medium" validator "IpAddress" 546 | string ftp_remote_username required display "medium" 547 | password ftp_remote_password display "medium" 548 | message ftp_encrypted_field_storage_help "Passwords and private keys are stored in an encrypted format. The salt for the encryption algorithm is the F5 cluster's Master Key. The master key is not shared when exporting a qkview or UCS, thus rendering your passwords and private keys safe if a backup file were to be stored off-box." 549 | string ftp_remote_directory display "medium" 550 | } 551 | editchoice filename_format display "xxlarge" tcl { 552 | set host [tmsh::get_field_value [lindex [tmsh::get_config sys global-settings] 0] hostname] 553 | set formats "" 554 | append formats {%Y%m%d%H%M%S_${host} => } 555 | append formats [clock format [clock seconds] -format "%Y%m%d%H%M%S_${host}"] 556 | append formats "\n" 557 | append formats {%Y%m%d_%H%M%S_${host} => } 558 | append formats [clock format [clock seconds] -format "%Y%m%d_%H%M%S_${host}"] 559 | append formats "\n" 560 | append formats {%Y%m%d_${host} => } 561 | append formats [clock format [clock seconds] -format "%Y%m%d_${host}"] 562 | append formats "\n" 563 | append formats {${host}_%Y%m%d%H%M%S => } 564 | append formats [clock format [clock seconds] -format "${host}_%Y%m%d%H%M%S"] 565 | append formats "\n" 566 | append formats {${host}_%Y%m%d_%H%M%S => } 567 | append formats [clock format [clock seconds] -format "${host}_%Y%m%d_%H%M%S"] 568 | append formats "\n" 569 | append formats {${host}_%Y%m%d => } 570 | append formats [clock format [clock seconds] -format "${host}_%Y%m%d"] 571 | append formats "\n" 572 | return $formats 573 | } 574 | message filename_format_help "You can select one, or create your own with all the [clock format] wildcards available in the tcl language, plus ${host} for the hostname. (http://www.tcl.tk/man/tcl8.6/TclCmd/clock.htm)" 575 | optional ( protocol_enable == "On this F5" ) { 576 | choice pruning_enable display "small" { "No", "Yes" } 577 | optional ( pruning_enable == "Yes" ) { 578 | editchoice keep_amount display "small" { "1", "2", "3", "4", "5", "6", "7", "8", "9", "10" } 579 | message pruning_help "Warning: if you decide to manually create a backupfile in the default directory, the automatic pruning will clean it if it doesn't match the 'newest X files' in that directory." 580 | } 581 | } 582 | } 583 | } 584 | text { 585 | deployment_info "Deployment Information" 586 | deployment_info.deployment_info_first_time "First Time Deployment:" 587 | deployment_info.deployment_info_updates "Testing the iApp:" 588 | deployment_info.deployment_info_logs "Logging:" 589 | backup_type "Backup Type" 590 | backup_type.backup_type_select "Select the type of backup:" 591 | backup_type.backup_passphrase_select "Use a passphrase to encrypt the UCS archive:" 592 | backup_type.backup_passphrase "What is the passphrase you want to use?" 593 | backup_type.backup_includeprivatekeys "Include the private keys in the archives?" 594 | backup_type.backup_help_scf "" 595 | backup_type.backup_help_passphrase "" 596 | backup_type.backup_help_privatekeys "" 597 | backup_schedule "Backup Schedule" 598 | backup_schedule.frequency_select "Frequency:" 599 | backup_schedule.everyxminutes_value "Where X equals:" 600 | backup_schedule.everyxhours_value "Where X equals:" 601 | backup_schedule.everyxhours_min_select "At what minute of each X hours should the backup occur?" 602 | backup_schedule.everyxdays_value "Where X equals:" 603 | backup_schedule.everyxdays_time "At what time on each X days should the backup occur? (Ex.: 15:25)" 604 | backup_schedule.everyxweeks_value "Where X equals:" 605 | backup_schedule.everyxweeks_time "At what time on the chosen day of each X weeks should the backup occur? (e.g. 04:15, 21:30)" 606 | backup_schedule.everyxweeks_dow_select "On what day of each X weeks should the backup should occur:" 607 | backup_schedule.everyxmonths_value "Where X equals:" 608 | backup_schedule.everyxmonths_time "At what time on the chosen day of each X months should the backup occur? (e.g. 04:15, 21:30)" 609 | backup_schedule.everyxmonths_dom_select "On what day of each X months should the backup should occur:" 610 | backup_schedule.custom_time "At what time on each selected day should the backup occur? (e.g. 04:15, 21:30)" 611 | backup_schedule.custom_dow_select "Choose the days of the week the backup should occur:" 612 | destination_parameters "Destination Parameters" 613 | destination_parameters.protocol_enable "Where do the backup files need to be saved?" 614 | destination_parameters.scp_sftp_help "SCP or SFTP?" 615 | destination_parameters.scp_remote_server "Destination IP:" 616 | destination_parameters.scp_remote_server_help "" 617 | destination_parameters.scp_stricthostkeychecking "StrictHostKeyChecking" 618 | destination_parameters.scp_stricthostkeychecking_help1 "" 619 | destination_parameters.scp_stricthostkeychecking_help2 "" 620 | destination_parameters.scp_stricthostkeychecking_trouble1 "" 621 | destination_parameters.scp_stricthostkeychecking_trouble2 "" 622 | destination_parameters.scp_stricthostkeychecking_warning1 "" 623 | destination_parameters.scp_remote_username "Username:" 624 | destination_parameters.scp_sshprivatekey "Copy/Paste the SSH private key to be used for passwordless authentication:" 625 | destination_parameters.scp_encrypted_field_storage_help "" 626 | destination_parameters.scp_encrypted_field_storage_help2 "" 627 | destination_parameters.scp_remote_directory "Remote directory for archive upload:" 628 | destination_parameters.scp_cipher "Cipher" 629 | destination_parameters.scp_cipher_help "" 630 | destination_parameters.smb_remote_server "Destination IP:" 631 | destination_parameters.smb_remote_server_help "" 632 | destination_parameters.smb_remote_username "Username:" 633 | destination_parameters.smb_remote_domain "Domain Name:" 634 | destination_parameters.smb_remote_domain_help "" 635 | destination_parameters.smb_remote_password "Password:" 636 | destination_parameters.smb_remote_password_help "" 637 | destination_parameters.smb_remote_password_help2 "" 638 | destination_parameters.smb_remote_path "SMB/CIFS share name:" 639 | destination_parameters.smb_remote_path_help "" 640 | destination_parameters.smb_remote_directory "Target path inside SMB Share:" 641 | destination_parameters.smb_remote_directory_help "" 642 | destination_parameters.smb_local_mountdir "Local mount point:" 643 | destination_parameters.smb_local_mountdir_help "" 644 | destination_parameters.ftp_remote_username "Username:" 645 | destination_parameters.ftp_remote_password "Password:" 646 | destination_parameters.ftp_encrypted_field_storage_help "" 647 | destination_parameters.ftp_remote_server "Destination IP:" 648 | destination_parameters.ftp_remote_directory "Set the remote directory the archive should be copied to:" 649 | destination_parameters.filename_format "Select the filename format:" 650 | destination_parameters.filename_format_help "" 651 | destination_parameters.pruning_enable "Activate automatic pruning?" 652 | destination_parameters.pruning_help "" 653 | destination_parameters.keep_amount "Amount of files to keep at any given time:" 654 | } 655 | } 656 | role-acl { admin manager resource-admin } 657 | run-as none 658 | } 659 | } 660 | description none 661 | ignore-verification false 662 | requires-bigip-version-max none 663 | requires-bigip-version-min 11.5.4 664 | requires-modules { ltm } 665 | signing-key none 666 | tmpl-checksum none 667 | tmpl-signature none 668 | } 669 | -------------------------------------------------------------------------------- /f5.automated_backup.v3.1.6.scripts.sh: -------------------------------------------------------------------------------- 1 | ========== 2 | SCP/SFTP 3 | ========== 4 | 5 | scp_function() 6 | { 7 | f5masterkey=\$(f5mku -K) 8 | username=\$(echo \"ENCRYPTEDUSERNAME\" | openssl aes-256-ecb -salt -a -A -d -k \${f5masterkey}) 9 | server=\$(echo \"ENCRYPTEDSERVER\" | openssl aes-256-ecb -salt -a -A -d -k \${f5masterkey}) 10 | directory=\$(echo \"ENCRYPTEDDIRECTORY\" | openssl aes-256-ecb -salt -a -A -d -k \${f5masterkey}) 11 | echo \"ENCRYPTEDPRIVATEKEY\" | openssl aes-256-ecb -salt -a -A -d -k \${f5masterkey} > /var/tmp/TMSHAPPNAME_scp.key 12 | 13 | chmod 600 /var/tmp/TMSHAPPNAME_scp.key 14 | scp -i /var/tmp/TMSHAPPNAME_scp.key SCPCIPHER SCPSTRICTHOSTKEYCHECKING BACKUPDIRECTORY/${fname_noext}BACKUPFILENAMEEXTENSION_WITHDOT* \${username}@\${server}:\${directory} 2>> /var/tmp/scriptd.out 15 | scp_result=\$? 16 | rm -f /var/tmp/TMSHAPPNAME_scp.key 17 | return \$scp_result 18 | } 19 | 20 | scp_function 21 | 22 | ========== 23 | FTP 24 | ========== 25 | 26 | ftp_function() 27 | { 28 | f5masterkey=\$(f5mku -K) 29 | username=\$(echo \"ENCRYPTEDUSERNAME\" | openssl aes-256-ecb -salt -a -A -d -k \${f5masterkey}) 30 | password=\$(echo \"ENCRYPTEDPASSWORD\" | openssl aes-256-ecb -salt -a -A -d -k \${f5masterkey}) 31 | server=\$(echo \"ENCRYPTEDSERVER\" | openssl aes-256-ecb -salt -a -A -d -k \${f5masterkey}) 32 | directory=\$(echo \"ENCRYPTEDDIRECTORY\" | openssl aes-256-ecb -salt -a -A -d -k \${f5masterkey}) 33 | 34 | if \[ \"BACKUPFILENAMEEXTENSION_NODOT\" == \"scf\" \] 35 | then 36 | ftp_return=\$(ftp -n \${server} << END_FTP 37 | quote USER \${username} 38 | quote PASS \${password} 39 | binary 40 | put BACKUPDIRECTORY/${fname_noext}BACKUPFILENAMEEXTENSION_WITHDOT \${directory}/${fname_noext}BACKUPFILENAMEEXTENSION_WITHDOT 41 | put BACKUPDIRECTORY/${fname_noext}BACKUPFILENAMEEXTENSION_WITHDOT.tar \${directory}/${fname_noext}BACKUPFILENAMEEXTENSION_WITHDOT.tar 42 | quit 43 | END_FTP 44 | ) 45 | else 46 | ftp_return=\$(ftp -n \${server} << END_FTP 47 | quote USER \${username} 48 | quote PASS \${password} 49 | binary 50 | put BACKUPDIRECTORY/${fname_noext}BACKUPFILENAMEEXTENSION_WITHDOT \${directory}/${fname_noext}BACKUPFILENAMEEXTENSION_WITHDOT 51 | quit 52 | END_FTP 53 | ) 54 | fi 55 | 56 | if \[ \"\$ftp_return\" == \"\" \] 57 | then 58 | return 0 59 | else 60 | echo \"\$ftp_return\" >> /var/tmp/scriptd.out 61 | return 1 62 | fi 63 | } 64 | 65 | ftp_function 66 | 67 | ========== 68 | SMB/CIFS 69 | ========== 70 | 71 | \#\!/bin/sh 72 | f5masterkey=\$(f5mku -K) 73 | username=\$(echo \"ENCRYPTEDUSERNAME\" | openssl aes-256-ecb -salt -a -A -d -k \${f5masterkey}) 74 | password=\$(echo \"ENCRYPTEDPASSWORD\" | openssl aes-256-ecb -salt -a -A -d -k \${f5masterkey}) 75 | msdomain=\$(echo \"ENCRYPTEDMSDOMAIN\" | openssl aes-256-ecb -salt -a -A -d -k \${f5masterkey}) 76 | server=\$(echo \"ENCRYPTEDSERVER\" | openssl aes-256-ecb -salt -a -A -d -k \${f5masterkey}) 77 | msshare=\$(echo \"ENCRYPTEDMSSHARE\" | openssl aes-256-ecb -salt -a -A -d -k \${f5masterkey}) 78 | mssubdir=\$(echo \"ENCRYPTEDMSSUBDIR\" | openssl aes-256-ecb -salt -a -A -d -k \${f5masterkey}) 79 | mountp=\$(echo \"ENCRYPTEDMOUNTP\" | openssl aes-256-ecb -salt -a -A -d -k \${f5masterkey}) 80 | cd BACKUPDIRECTORY 81 | if \[ \! -d \${mountp} \] 82 | then 83 | mkdir -p \${mountp} 84 | if \[ \$? -ne 0 \] 85 | then 86 | rm -f ${fname_noext}BACKUPFILENAMEEXTENSION_WITHDOT* 87 | exit 1 88 | fi 89 | fi 90 | mount -t cifs //\${server}/\${msshare}\${mssubdir} \${mountp} -o user=\${username}%\${password},domain=\${msdomain} 2>> /var/tmp/scriptd.out 91 | if \[ \$? -ne 0 \] 92 | then 93 | echo \"DEBUG: Failed to mount //\${server}/\${msshare}\${mssubdir}\ to \${mountp}\" >> /var/tmp/scriptd.out 94 | rm -f ${fname_noext}BACKUPFILENAMEEXTENSION_WITHDOT* 95 | exit 1 96 | else 97 | echo \"DEBUG: Successfully mounted //\${server}/\${msshare}\${mssubdir}\ to \${mountp}\" >> /var/tmp/scriptd.out 98 | fi 99 | 100 | latestFileOnSMB=\$(ls -t \${mountp}/\*.BACKUPFILENAMEEXTENSION_NODOT 2>/dev/null| head -n 1 2>/dev/null) 101 | echo \"DEBUG: Latest BACKUPFILENAMEEXTENSION_NODOT file found on SMB mount: \$latestFileOnSMB\" >> /var/tmp/scriptd.out 102 | 103 | if \[ \"X\"\${latestFileOnSMB} \!= \"X\" \] 104 | then 105 | sum1=\$(md5sum ${fname_noext}BACKUPFILENAMEEXTENSION_WITHDOT | awk '{print \$1}') 106 | sum2=\$(md5sum \${latestFileOnSMB} | awk \'{print \$1}\') 107 | if \[ \${sum1} == \${sum2} \] 108 | then 109 | echo \"ERROR: File ${fname_noext}BACKUPFILENAMEEXTENSION_WITHDOT already exists in //\${server}/\${msshare}\${mssubdir}\" >> /var/tmp/scriptd.out 110 | umount \${mountp} 111 | rm -f ${fname_noext}BACKUPFILENAMEEXTENSION_WITHDOT* 112 | exit 1 113 | else 114 | echo \"DEBUG: File ${fname_noext}BACKUPFILENAMEEXTENSION_WITHDOT does not already exist in //\${server}/\${msshare}\${mssubdir} (continuing...)\" >> /var/tmp/scriptd.out 115 | fi 116 | else 117 | echo \"DEBUG: Destination SMB mount contains no BACKUPFILENAMEEXTENSION_NODOT files (continuing...)\" >> /var/tmp/scriptd.out 118 | fi 119 | cp ${fname_noext}BACKUPFILENAMEEXTENSION_WITHDOT* \${mountp} 120 | rm -f ${fname_noext}BACKUPFILENAMEEXTENSION_WITHDOT* 121 | 122 | if \[ \"PRUNINGMODE\" \!= \"Disabled\" \]; then 123 | 124 | files_tokeep=\$(ls -t \${mountp}/*PRUNINGSUFFIX.BACKUPFILENAMEEXTENSION_NODOT 2>/dev/null | head -n CONSERVE\) 125 | for current_archive_file in `ls \${mountp}/*PRUNINGSUFFIX.BACKUPFILENAMEEXTENSION_NODOT 2>/dev/null` ; do 126 | current_archive_file_basename=`basename \$current_archive_file` 127 | check_file=\$(echo \$files_tokeep | grep -w \$current_archive_file_basename) 128 | if \[ \"\$check_file\" == \"\" \] ; then 129 | rm -f \$current_archive_file 130 | fi 131 | done 132 | if \[ \"BACKUPFILENAMEEXTENSION_NODOT\" == \"scf\" \] ; then 133 | tar_files_tokeep=\$(ls -t \${mountp}/*PRUNINGSUFFIX.BACKUPFILENAMEEXTENSION_NODOT.tar 2>/dev/null | head -n CONSERVE\) 134 | for current_archive_tar_file in `ls \${mountp}/*PRUNINGSUFFIX.BACKUPFILENAMEEXTENSION_NODOT.tar 2>/dev/null` ; do 135 | current_archive_tar_file_basename=`basename \$current_archive_tar_file` 136 | check_file=\$(echo \$tar_files_tokeep | grep -w \$current_archive_tar_file_basename) 137 | if \[ \"\$check_file\" == \"\" \] ; then 138 | rm -f \$current_archive_tar_file 139 | fi 140 | done 141 | fi 142 | fi 143 | 144 | umount \${mountp} 145 | 146 | exit 0 147 | 148 | ========== 149 | LOCAL PRUNING 150 | ========== 151 | 152 | files_tokeep=\$(ls -t BACKUPDIRECTORY/*PRUNINGSUFFIX.BACKUPFILENAMEEXTENSION_NODOT 2>/dev/null | head -n CONSERVE\) 153 | for current_archive_file in `ls BACKUPDIRECTORY/*PRUNINGSUFFIX.BACKUPFILENAMEEXTENSION_NODOT 2>/dev/null` ; do 154 | current_archive_file_basename=`basename \$current_archive_file` 155 | check_file=\$(echo \$files_tokeep | grep -w \$current_archive_file_basename) 156 | if \[ \"\$check_file\" == \"\" \] ; then 157 | rm -f \$current_archive_file 158 | fi 159 | done 160 | if \[ \"BACKUPFILENAMEEXTENSION_NODOT\" == \"scf\" \] ; then 161 | tar_files_tokeep=\$(ls -t BACKUPDIRECTORY/*PRUNINGSUFFIX.BACKUPFILENAMEEXTENSION_NODOT.tar 2>/dev/null | head -n CONSERVE\) 162 | for current_archive_tar_file in `ls BACKUPDIRECTORY/*PRUNINGSUFFIX.BACKUPFILENAMEEXTENSION_NODOT.tar 2>/dev/null` ; do 163 | current_archive_tar_file_basename=`basename \$current_archive_tar_file` 164 | check_file=\$(echo \$tar_files_tokeep | grep -w \$current_archive_tar_file_basename) 165 | if \[ \"\$check_file\" == \"\" \] ; then 166 | rm -f \$current_archive_tar_file 167 | fi 168 | done 169 | fi 170 | -------------------------------------------------------------------------------- /f5.automated_backup.v3.1.7.scripts.sh: -------------------------------------------------------------------------------- 1 | ========== 2 | SCP/SFTP 3 | ========== 4 | 5 | scp_function() 6 | { 7 | f5masterkey=\$(f5mku -K) 8 | username=\$(echo \"ENCRYPTEDUSERNAME\" | openssl aes-256-ecb -salt -a -A -d -k \${f5masterkey}) 9 | server=\$(echo \"ENCRYPTEDSERVER\" | openssl aes-256-ecb -salt -a -A -d -k \${f5masterkey}) 10 | directory=\$(echo \"ENCRYPTEDDIRECTORY\" | openssl aes-256-ecb -salt -a -A -d -k \${f5masterkey}) 11 | echo \"ENCRYPTEDPRIVATEKEY\" | openssl aes-256-ecb -salt -a -A -d -k \${f5masterkey} > /var/tmp/TMSHAPPNAME_scp.key 12 | 13 | chmod 600 /var/tmp/TMSHAPPNAME_scp.key 14 | scp -i /var/tmp/TMSHAPPNAME_scp.key SCPCIPHER SCPSTRICTHOSTKEYCHECKING BACKUPDIRECTORY/${fname_noext}BACKUPFILENAMEEXTENSION_WITHDOT* \${username}@\${server}:\${directory} 2>> /var/tmp/scriptd.out 15 | scp_result=\$? 16 | rm -f /var/tmp/TMSHAPPNAME_scp.key 17 | return \$scp_result 18 | } 19 | 20 | scp_function 21 | 22 | ========== 23 | FTP 24 | ========== 25 | 26 | ftp_function() 27 | { 28 | f5masterkey=\$(f5mku -K) 29 | username=\$(echo \"ENCRYPTEDUSERNAME\" | openssl aes-256-ecb -salt -a -A -d -k \${f5masterkey}) 30 | password=\$(echo \"ENCRYPTEDPASSWORD\" | openssl aes-256-ecb -salt -a -A -d -k \${f5masterkey}) 31 | # Escape every character for safe submission of special characters in the password 32 | password_escaped=\$(echo \${password} | sed \'s/./\\\\\\&/g\') 33 | server=\$(echo \"ENCRYPTEDSERVER\" | openssl aes-256-ecb -salt -a -A -d -k \${f5masterkey}) 34 | directory=\$(echo \"ENCRYPTEDDIRECTORY\" | openssl aes-256-ecb -salt -a -A -d -k \${f5masterkey}) 35 | 36 | if \[ \"BACKUPFILENAMEEXTENSION_NODOT\" == \"scf\" \] 37 | then 38 | ftp_return=\$(ftp -n \${server} << END_FTP 39 | quote USER \${username} 40 | quote PASS \${password_escaped} 41 | binary 42 | put BACKUPDIRECTORY/${fname_noext}BACKUPFILENAMEEXTENSION_WITHDOT \${directory}/${fname_noext}BACKUPFILENAMEEXTENSION_WITHDOT 43 | put BACKUPDIRECTORY/${fname_noext}BACKUPFILENAMEEXTENSION_WITHDOT.tar \${directory}/${fname_noext}BACKUPFILENAMEEXTENSION_WITHDOT.tar 44 | quit 45 | END_FTP 46 | ) 47 | else 48 | ftp_return=\$(ftp -n \${server} << END_FTP 49 | quote USER \${username} 50 | quote PASS \${password_escaped} 51 | binary 52 | put BACKUPDIRECTORY/${fname_noext}BACKUPFILENAMEEXTENSION_WITHDOT \${directory}/${fname_noext}BACKUPFILENAMEEXTENSION_WITHDOT 53 | quit 54 | END_FTP 55 | ) 56 | fi 57 | 58 | if \[ \"\$ftp_return\" == \"\" \] 59 | then 60 | return 0 61 | else 62 | echo \"\$ftp_return\" >> /var/tmp/scriptd.out 63 | return 1 64 | fi 65 | } 66 | 67 | ftp_function 68 | 69 | ========== 70 | SMB/CIFS 71 | ========== 72 | 73 | \#\!/bin/sh 74 | f5masterkey=\$(f5mku -K) 75 | username=\$(echo \"ENCRYPTEDUSERNAME\" | openssl aes-256-ecb -salt -a -A -d -k \${f5masterkey}) 76 | password=\$(echo \"ENCRYPTEDPASSWORD\" | openssl aes-256-ecb -salt -a -A -d -k \${f5masterkey}) 77 | msdomain=\$(echo \"ENCRYPTEDMSDOMAIN\" | openssl aes-256-ecb -salt -a -A -d -k \${f5masterkey}) 78 | server=\$(echo \"ENCRYPTEDSERVER\" | openssl aes-256-ecb -salt -a -A -d -k \${f5masterkey}) 79 | msshare=\$(echo \"ENCRYPTEDMSSHARE\" | openssl aes-256-ecb -salt -a -A -d -k \${f5masterkey}) 80 | mssubdir=\$(echo \"ENCRYPTEDMSSUBDIR\" | openssl aes-256-ecb -salt -a -A -d -k \${f5masterkey}) 81 | mountp=\$(echo \"ENCRYPTEDMOUNTP\" | openssl aes-256-ecb -salt -a -A -d -k \${f5masterkey}) 82 | cd BACKUPDIRECTORY 83 | if \[ \! -d \${mountp} \] 84 | then 85 | mkdir -p \${mountp} 86 | if \[ \$? -ne 0 \] 87 | then 88 | rm -f ${fname_noext}BACKUPFILENAMEEXTENSION_WITHDOT* 89 | exit 1 90 | fi 91 | fi 92 | # The password must be surrounded by two single-quotes (e.g. ''${password}'') to successfully handle special characters. Still does not support comma, single-quote, and double-quote. 93 | mount -t cifs //\${server}/\${msshare}\${mssubdir} \${mountp} -o user=\${username}%\'\'\${password}\'\',domain=\${msdomain} 2>> /var/tmp/scriptd.out 94 | if \[ \$? -ne 0 \] 95 | then 96 | echo \"DEBUG: Failed to mount //\${server}/\${msshare}\${mssubdir}\ to \${mountp}\" >> /var/tmp/scriptd.out 97 | rm -f ${fname_noext}BACKUPFILENAMEEXTENSION_WITHDOT* 98 | exit 1 99 | else 100 | echo \"DEBUG: Successfully mounted //\${server}/\${msshare}\${mssubdir}\ to \${mountp}\" >> /var/tmp/scriptd.out 101 | fi 102 | 103 | latestFileOnSMB=\$(ls -t \${mountp}/\*.BACKUPFILENAMEEXTENSION_NODOT 2>/dev/null| head -n 1 2>/dev/null) 104 | echo \"DEBUG: Latest BACKUPFILENAMEEXTENSION_NODOT file found on SMB mount: \$latestFileOnSMB\" >> /var/tmp/scriptd.out 105 | 106 | if \[ \"X\"\${latestFileOnSMB} \!= \"X\" \] 107 | then 108 | sum1=\$(md5sum ${fname_noext}BACKUPFILENAMEEXTENSION_WITHDOT | awk '{print \$1}') 109 | sum2=\$(md5sum \${latestFileOnSMB} | awk \'{print \$1}\') 110 | if \[ \${sum1} == \${sum2} \] 111 | then 112 | echo \"ERROR: File ${fname_noext}BACKUPFILENAMEEXTENSION_WITHDOT already exists in //\${server}/\${msshare}\${mssubdir}\" >> /var/tmp/scriptd.out 113 | umount \${mountp} 114 | rm -f ${fname_noext}BACKUPFILENAMEEXTENSION_WITHDOT* 115 | exit 1 116 | else 117 | echo \"DEBUG: File ${fname_noext}BACKUPFILENAMEEXTENSION_WITHDOT does not already exist in //\${server}/\${msshare}\${mssubdir} (continuing...)\" >> /var/tmp/scriptd.out 118 | fi 119 | else 120 | echo \"DEBUG: Destination SMB mount contains no BACKUPFILENAMEEXTENSION_NODOT files (continuing...)\" >> /var/tmp/scriptd.out 121 | fi 122 | cp ${fname_noext}BACKUPFILENAMEEXTENSION_WITHDOT* \${mountp} 123 | rm -f ${fname_noext}BACKUPFILENAMEEXTENSION_WITHDOT* 124 | 125 | if \[ \"PRUNINGMODE\" \!= \"Disabled\" \]; then 126 | 127 | files_tokeep=\$(ls -t \${mountp}/*PRUNINGSUFFIX.BACKUPFILENAMEEXTENSION_NODOT 2>/dev/null | head -n CONSERVE\) 128 | for current_archive_file in `ls \${mountp}/*PRUNINGSUFFIX.BACKUPFILENAMEEXTENSION_NODOT 2>/dev/null` ; do 129 | current_archive_file_basename=`basename \$current_archive_file` 130 | check_file=\$(echo \$files_tokeep | grep -w \$current_archive_file_basename) 131 | if \[ \"\$check_file\" == \"\" \] ; then 132 | rm -f \$current_archive_file 133 | fi 134 | done 135 | if \[ \"BACKUPFILENAMEEXTENSION_NODOT\" == \"scf\" \] ; then 136 | tar_files_tokeep=\$(ls -t \${mountp}/*PRUNINGSUFFIX.BACKUPFILENAMEEXTENSION_NODOT.tar 2>/dev/null | head -n CONSERVE\) 137 | for current_archive_tar_file in `ls \${mountp}/*PRUNINGSUFFIX.BACKUPFILENAMEEXTENSION_NODOT.tar 2>/dev/null` ; do 138 | current_archive_tar_file_basename=`basename \$current_archive_tar_file` 139 | check_file=\$(echo \$tar_files_tokeep | grep -w \$current_archive_tar_file_basename) 140 | if \[ \"\$check_file\" == \"\" \] ; then 141 | rm -f \$current_archive_tar_file 142 | fi 143 | done 144 | fi 145 | fi 146 | 147 | umount \${mountp} 148 | 149 | exit 0 150 | 151 | ========== 152 | LOCAL PRUNING 153 | ========== 154 | 155 | files_tokeep=\$(ls -t BACKUPDIRECTORY/*PRUNINGSUFFIX.BACKUPFILENAMEEXTENSION_NODOT 2>/dev/null | head -n CONSERVE\) 156 | for current_archive_file in `ls BACKUPDIRECTORY/*PRUNINGSUFFIX.BACKUPFILENAMEEXTENSION_NODOT 2>/dev/null` ; do 157 | current_archive_file_basename=`basename \$current_archive_file` 158 | check_file=\$(echo \$files_tokeep | grep -w \$current_archive_file_basename) 159 | if \[ \"\$check_file\" == \"\" \] ; then 160 | rm -f \$current_archive_file 161 | fi 162 | done 163 | if \[ \"BACKUPFILENAMEEXTENSION_NODOT\" == \"scf\" \] ; then 164 | tar_files_tokeep=\$(ls -t BACKUPDIRECTORY/*PRUNINGSUFFIX.BACKUPFILENAMEEXTENSION_NODOT.tar 2>/dev/null | head -n CONSERVE\) 165 | for current_archive_tar_file in `ls BACKUPDIRECTORY/*PRUNINGSUFFIX.BACKUPFILENAMEEXTENSION_NODOT.tar 2>/dev/null` ; do 166 | current_archive_tar_file_basename=`basename \$current_archive_tar_file` 167 | check_file=\$(echo \$tar_files_tokeep | grep -w \$current_archive_tar_file_basename) 168 | if \[ \"\$check_file\" == \"\" \] ; then 169 | rm -f \$current_archive_tar_file 170 | fi 171 | done 172 | fi 173 | -------------------------------------------------------------------------------- /f5.automated_backup.v3.1.8.scripts.sh: -------------------------------------------------------------------------------- 1 | ========== 2 | SCP/SFTP 3 | ========== 4 | 5 | scp_function() 6 | { 7 | f5masterkey=\$(f5mku -K) 8 | username=\$(echo \"ENCRYPTEDUSERNAME\" | openssl aes-256-ecb -salt -a -A -d -k \${f5masterkey}) 9 | server=\$(echo \"ENCRYPTEDSERVER\" | openssl aes-256-ecb -salt -a -A -d -k \${f5masterkey}) 10 | directory=\$(echo \"ENCRYPTEDDIRECTORY\" | openssl aes-256-ecb -salt -a -A -d -k \${f5masterkey}) 11 | echo \"ENCRYPTEDPRIVATEKEY\" | openssl aes-256-ecb -salt -a -A -d -k \${f5masterkey} > /var/tmp/TMSHAPPNAME_scp.key 12 | 13 | chmod 600 /var/tmp/TMSHAPPNAME_scp.key 14 | scp -i /var/tmp/TMSHAPPNAME_scp.key SCPCIPHER SCPSTRICTHOSTKEYCHECKING BACKUPDIRECTORY/${fname_noext}BACKUPFILENAMEEXTENSION_WITHDOT* \${username}@\${server}:\${directory} 2>> /var/tmp/scriptd.out 15 | scp_result=\$? 16 | rm -f /var/tmp/TMSHAPPNAME_scp.key 17 | return \$scp_result 18 | } 19 | 20 | scp_function 21 | 22 | ========== 23 | FTP 24 | ========== 25 | 26 | ftp_function() 27 | { 28 | f5masterkey=\$(f5mku -K) 29 | username=\$(echo \"ENCRYPTEDUSERNAME\" | openssl aes-256-ecb -salt -a -A -d -k \${f5masterkey}) 30 | password=\$(echo \"ENCRYPTEDPASSWORD\" | openssl aes-256-ecb -salt -a -A -d -k \${f5masterkey}) 31 | # Escape every character for safe submission of special characters in the password 32 | password_escaped=\$(echo \${password} | sed \'s/./\\\\\\&/g\') 33 | server=\$(echo \"ENCRYPTEDSERVER\" | openssl aes-256-ecb -salt -a -A -d -k \${f5masterkey}) 34 | directory=\$(echo \"ENCRYPTEDDIRECTORY\" | openssl aes-256-ecb -salt -a -A -d -k \${f5masterkey}) 35 | 36 | if \[ \"BACKUPFILENAMEEXTENSION_NODOT\" == \"scf\" \] 37 | then 38 | ftp_return=\$(ftp -n \${server} << END_FTP 39 | quote USER \${username} 40 | quote PASS \${password_escaped} 41 | binary 42 | put BACKUPDIRECTORY/${fname_noext}BACKUPFILENAMEEXTENSION_WITHDOT \${directory}/${fname_noext}BACKUPFILENAMEEXTENSION_WITHDOT 43 | put BACKUPDIRECTORY/${fname_noext}BACKUPFILENAMEEXTENSION_WITHDOT.tar \${directory}/${fname_noext}BACKUPFILENAMEEXTENSION_WITHDOT.tar 44 | quit 45 | END_FTP 46 | ) 47 | else 48 | ftp_return=\$(ftp -n \${server} << END_FTP 49 | quote USER \${username} 50 | quote PASS \${password_escaped} 51 | binary 52 | put BACKUPDIRECTORY/${fname_noext}BACKUPFILENAMEEXTENSION_WITHDOT \${directory}/${fname_noext}BACKUPFILENAMEEXTENSION_WITHDOT 53 | quit 54 | END_FTP 55 | ) 56 | fi 57 | 58 | if \[ \"\$ftp_return\" == \"\" \] 59 | then 60 | return 0 61 | else 62 | echo \"\$ftp_return\" >> /var/tmp/scriptd.out 63 | return 1 64 | fi 65 | } 66 | 67 | ftp_function 68 | 69 | ========== 70 | SMB/CIFS 71 | ========== 72 | 73 | \#\!/bin/sh 74 | f5masterkey=\$(f5mku -K) 75 | username=\$(echo \"ENCRYPTEDUSERNAME\" | openssl aes-256-ecb -salt -a -A -d -k \${f5masterkey}) 76 | password=\$(echo \"ENCRYPTEDPASSWORD\" | openssl aes-256-ecb -salt -a -A -d -k \${f5masterkey}) 77 | msdomain=\$(echo \"ENCRYPTEDMSDOMAIN\" | openssl aes-256-ecb -salt -a -A -d -k \${f5masterkey}) 78 | server=\$(echo \"ENCRYPTEDSERVER\" | openssl aes-256-ecb -salt -a -A -d -k \${f5masterkey}) 79 | msshare=\$(echo \"ENCRYPTEDMSSHARE\" | openssl aes-256-ecb -salt -a -A -d -k \${f5masterkey}) 80 | mssubdir=\$(echo \"ENCRYPTEDMSSUBDIR\" | openssl aes-256-ecb -salt -a -A -d -k \${f5masterkey}) 81 | mountp=\$(echo \"ENCRYPTEDMOUNTP\" | openssl aes-256-ecb -salt -a -A -d -k \${f5masterkey}) 82 | cd BACKUPDIRECTORY 83 | if \[ \! -d \${mountp} \] 84 | then 85 | mkdir -p \${mountp} 86 | if \[ \$? -ne 0 \] 87 | then 88 | rm -f ${fname_noext}BACKUPFILENAMEEXTENSION_WITHDOT* 89 | exit 1 90 | fi 91 | fi 92 | # The password must be surrounded by two single-quotes (e.g. ''${password}'') to successfully handle special characters. Still does not support comma, single-quote, and double-quote. 93 | mount -t cifs //\${server}/\${msshare}\${mssubdir} \${mountp} -o user=\${username}%\'\'\${password}\'\',domain=\${msdomain} 2>> /var/tmp/scriptd.out 94 | if \[ \$? -ne 0 \] 95 | then 96 | echo \"DEBUG: Failed to mount //\${server}/\${msshare}\${mssubdir}\ to \${mountp}\" >> /var/tmp/scriptd.out 97 | rm -f ${fname_noext}BACKUPFILENAMEEXTENSION_WITHDOT* 98 | exit 1 99 | else 100 | echo \"DEBUG: Successfully mounted //\${server}/\${msshare}\${mssubdir}\ to \${mountp}\" >> /var/tmp/scriptd.out 101 | fi 102 | 103 | latestFileOnSMB=\$(ls -t \${mountp}/\*.BACKUPFILENAMEEXTENSION_NODOT 2>/dev/null| head -n 1 2>/dev/null) 104 | echo \"DEBUG: Latest BACKUPFILENAMEEXTENSION_NODOT file found on SMB mount: \$latestFileOnSMB\" >> /var/tmp/scriptd.out 105 | 106 | if \[ \"X\"\${latestFileOnSMB} \!= \"X\" \] 107 | then 108 | sum1=\$(md5sum ${fname_noext}BACKUPFILENAMEEXTENSION_WITHDOT | awk '{print \$1}') 109 | sum2=\$(md5sum \${latestFileOnSMB} | awk \'{print \$1}\') 110 | if \[ \${sum1} == \${sum2} \] 111 | then 112 | echo \"ERROR: File ${fname_noext}BACKUPFILENAMEEXTENSION_WITHDOT already exists in //\${server}/\${msshare}\${mssubdir}\" >> /var/tmp/scriptd.out 113 | umount \${mountp} 114 | rm -f ${fname_noext}BACKUPFILENAMEEXTENSION_WITHDOT* 115 | exit 1 116 | else 117 | echo \"DEBUG: File ${fname_noext}BACKUPFILENAMEEXTENSION_WITHDOT does not already exist in //\${server}/\${msshare}\${mssubdir} (continuing...)\" >> /var/tmp/scriptd.out 118 | fi 119 | else 120 | echo \"DEBUG: Destination SMB mount contains no BACKUPFILENAMEEXTENSION_NODOT files (continuing...)\" >> /var/tmp/scriptd.out 121 | fi 122 | cp ${fname_noext}BACKUPFILENAMEEXTENSION_WITHDOT* \${mountp} 123 | rm -f ${fname_noext}BACKUPFILENAMEEXTENSION_WITHDOT* 124 | 125 | if \[ \"PRUNINGMODE\" \!= \"Disabled\" \]; then 126 | 127 | files_tokeep=\$(ls -t \${mountp}/*PRUNINGSUFFIX.BACKUPFILENAMEEXTENSION_NODOT 2>/dev/null | head -n CONSERVE\) 128 | for current_archive_file in `ls \${mountp}/*PRUNINGSUFFIX.BACKUPFILENAMEEXTENSION_NODOT 2>/dev/null` ; do 129 | current_archive_file_basename=`basename \$current_archive_file` 130 | check_file=\$(echo \$files_tokeep | grep -w \$current_archive_file_basename) 131 | if \[ \"\$check_file\" == \"\" \] ; then 132 | rm -f \$current_archive_file 133 | fi 134 | done 135 | if \[ \"BACKUPFILENAMEEXTENSION_NODOT\" == \"scf\" \] ; then 136 | tar_files_tokeep=\$(ls -t \${mountp}/*PRUNINGSUFFIX.BACKUPFILENAMEEXTENSION_NODOT.tar 2>/dev/null | head -n CONSERVE\) 137 | for current_archive_tar_file in `ls \${mountp}/*PRUNINGSUFFIX.BACKUPFILENAMEEXTENSION_NODOT.tar 2>/dev/null` ; do 138 | current_archive_tar_file_basename=`basename \$current_archive_tar_file` 139 | check_file=\$(echo \$tar_files_tokeep | grep -w \$current_archive_tar_file_basename) 140 | if \[ \"\$check_file\" == \"\" \] ; then 141 | rm -f \$current_archive_tar_file 142 | fi 143 | done 144 | fi 145 | fi 146 | 147 | umount \${mountp} 148 | 149 | exit 0 150 | 151 | ========== 152 | LOCAL PRUNING 153 | ========== 154 | 155 | files_tokeep=\$(ls -t BACKUPDIRECTORY/*PRUNINGSUFFIX.BACKUPFILENAMEEXTENSION_NODOT 2>/dev/null | head -n CONSERVE\) 156 | for current_archive_file in `ls BACKUPDIRECTORY/*PRUNINGSUFFIX.BACKUPFILENAMEEXTENSION_NODOT 2>/dev/null` ; do 157 | current_archive_file_basename=`basename \$current_archive_file` 158 | check_file=\$(echo \$files_tokeep | grep -w \$current_archive_file_basename) 159 | if \[ \"\$check_file\" == \"\" \] ; then 160 | rm -f \$current_archive_file 161 | fi 162 | done 163 | if \[ \"BACKUPFILENAMEEXTENSION_NODOT\" == \"scf\" \] ; then 164 | tar_files_tokeep=\$(ls -t BACKUPDIRECTORY/*PRUNINGSUFFIX.BACKUPFILENAMEEXTENSION_NODOT.tar 2>/dev/null | head -n CONSERVE\) 165 | for current_archive_tar_file in `ls BACKUPDIRECTORY/*PRUNINGSUFFIX.BACKUPFILENAMEEXTENSION_NODOT.tar 2>/dev/null` ; do 166 | current_archive_tar_file_basename=`basename \$current_archive_tar_file` 167 | check_file=\$(echo \$tar_files_tokeep | grep -w \$current_archive_tar_file_basename) 168 | if \[ \"\$check_file\" == \"\" \] ; then 169 | rm -f \$current_archive_tar_file 170 | fi 171 | done 172 | fi 173 | -------------------------------------------------------------------------------- /f5.automated_backup.v3.1.9.scripts.sh: -------------------------------------------------------------------------------- 1 | ========== 2 | SCP/SFTP 3 | ========== 4 | 5 | scp_function() 6 | { 7 | f5masterkey=\$(f5mku -K) 8 | username=\$(echo \"ENCRYPTEDUSERNAME\" | openssl aes-256-ecb -salt -a -A -d -k \${f5masterkey}) 9 | server=\$(echo \"ENCRYPTEDSERVER\" | openssl aes-256-ecb -salt -a -A -d -k \${f5masterkey}) 10 | directory=\$(echo \"ENCRYPTEDDIRECTORY\" | openssl aes-256-ecb -salt -a -A -d -k \${f5masterkey}) 11 | echo \"ENCRYPTEDPRIVATEKEY\" | openssl aes-256-ecb -salt -a -A -d -k \${f5masterkey} > /var/tmp/TMSHAPPNAME_scp.key 12 | 13 | chmod 600 /var/tmp/TMSHAPPNAME_scp.key 14 | scp -i /var/tmp/TMSHAPPNAME_scp.key SCPCIPHER SCPSTRICTHOSTKEYCHECKING BACKUPDIRECTORY/${fname_noext}BACKUPFILENAMEEXTENSION_WITHDOT* \${username}@\${server}:\${directory} 2>> /var/tmp/scriptd.out 15 | scp_result=\$? 16 | rm -f /var/tmp/TMSHAPPNAME_scp.key 17 | return \$scp_result 18 | } 19 | 20 | scp_function 21 | 22 | ========== 23 | FTP 24 | ========== 25 | 26 | ftp_function() 27 | { 28 | f5masterkey=\$(f5mku -K) 29 | username=\$(echo \"ENCRYPTEDUSERNAME\" | openssl aes-256-ecb -salt -a -A -d -k \${f5masterkey}) 30 | password=\$(echo \"ENCRYPTEDPASSWORD\" | openssl aes-256-ecb -salt -a -A -d -k \${f5masterkey}) 31 | # Escape every character for safe submission of special characters in the password 32 | password_escaped=\$(echo \${password} | sed \'s/./\\\\\\&/g\') 33 | server=\$(echo \"ENCRYPTEDSERVER\" | openssl aes-256-ecb -salt -a -A -d -k \${f5masterkey}) 34 | directory=\$(echo \"ENCRYPTEDDIRECTORY\" | openssl aes-256-ecb -salt -a -A -d -k \${f5masterkey}) 35 | 36 | if \[ \"BACKUPFILENAMEEXTENSION_NODOT\" == \"scf\" \] 37 | then 38 | ftp_return=\$(ftp -n \${server} << END_FTP 39 | quote USER \${username} 40 | quote PASS \${password_escaped} 41 | binary 42 | put BACKUPDIRECTORY/${fname_noext}BACKUPFILENAMEEXTENSION_WITHDOT \${directory}/${fname_noext}BACKUPFILENAMEEXTENSION_WITHDOT 43 | put BACKUPDIRECTORY/${fname_noext}BACKUPFILENAMEEXTENSION_WITHDOT.tar \${directory}/${fname_noext}BACKUPFILENAMEEXTENSION_WITHDOT.tar 44 | quit 45 | END_FTP 46 | ) 47 | else 48 | ftp_return=\$(ftp -n \${server} << END_FTP 49 | quote USER \${username} 50 | quote PASS \${password_escaped} 51 | binary 52 | put BACKUPDIRECTORY/${fname_noext}BACKUPFILENAMEEXTENSION_WITHDOT \${directory}/${fname_noext}BACKUPFILENAMEEXTENSION_WITHDOT 53 | quit 54 | END_FTP 55 | ) 56 | fi 57 | 58 | if \[ \"\$ftp_return\" == \"\" \] 59 | then 60 | return 0 61 | else 62 | echo \"\$ftp_return\" >> /var/tmp/scriptd.out 63 | return 1 64 | fi 65 | } 66 | 67 | ftp_function 68 | 69 | ========== 70 | SMB/CIFS 71 | ========== 72 | 73 | \#\!/bin/sh 74 | f5masterkey=\$(f5mku -K) 75 | username=\$(echo \"ENCRYPTEDUSERNAME\" | openssl aes-256-ecb -salt -a -A -d -k \${f5masterkey}) 76 | password=\$(echo \"ENCRYPTEDPASSWORD\" | openssl aes-256-ecb -salt -a -A -d -k \${f5masterkey}) 77 | msdomain=\$(echo \"ENCRYPTEDMSDOMAIN\" | openssl aes-256-ecb -salt -a -A -d -k \${f5masterkey}) 78 | server=\$(echo \"ENCRYPTEDSERVER\" | openssl aes-256-ecb -salt -a -A -d -k \${f5masterkey}) 79 | msshare=\$(echo \"ENCRYPTEDMSSHARE\" | openssl aes-256-ecb -salt -a -A -d -k \${f5masterkey}) 80 | mssubdir=\$(echo \"ENCRYPTEDMSSUBDIR\" | openssl aes-256-ecb -salt -a -A -d -k \${f5masterkey}) 81 | mountp=\$(echo \"ENCRYPTEDMOUNTP\" | openssl aes-256-ecb -salt -a -A -d -k \${f5masterkey}) 82 | cd BACKUPDIRECTORY 83 | if \[ \! -d \${mountp} \] 84 | then 85 | mkdir -p \${mountp} 86 | if \[ \$? -ne 0 \] 87 | then 88 | rm -f ${fname_noext}BACKUPFILENAMEEXTENSION_WITHDOT* 89 | exit 1 90 | fi 91 | fi 92 | \# The password must be surrounded by two single-quotes to successfully handle special characters. Still does not support comma, single-quote, and double-quote. 93 | mount -t cifs //\${server}/\${msshare}\${mssubdir} \${mountp} -o user=\${username}%\'\'\${password}\'\',domain=\${msdomain} 2>> /var/tmp/scriptd.out 94 | if \[ \$? -ne 0 \] 95 | then 96 | echo \"DEBUG: Failed to mount //\${server}/\${msshare}\${mssubdir}\ to \${mountp}\" >> /var/tmp/scriptd.out 97 | rm -f ${fname_noext}BACKUPFILENAMEEXTENSION_WITHDOT* 98 | exit 1 99 | else 100 | echo \"DEBUG: Successfully mounted //\${server}/\${msshare}\${mssubdir}\ to \${mountp}\" >> /var/tmp/scriptd.out 101 | fi 102 | 103 | latestFileOnSMB=\$(ls -t \${mountp}/\*.BACKUPFILENAMEEXTENSION_NODOT 2>/dev/null| head -n 1 2>/dev/null) 104 | echo \"DEBUG: Latest BACKUPFILENAMEEXTENSION_NODOT file found on SMB mount: \$latestFileOnSMB\" >> /var/tmp/scriptd.out 105 | 106 | if \[ \"X\"\${latestFileOnSMB} \!= \"X\" \] 107 | then 108 | sum1=\$(md5sum ${fname_noext}BACKUPFILENAMEEXTENSION_WITHDOT | awk '{print \$1}') 109 | sum2=\$(md5sum \${latestFileOnSMB} | awk \'{print \$1}\') 110 | if \[ \${sum1} == \${sum2} \] 111 | then 112 | echo \"ERROR: File ${fname_noext}BACKUPFILENAMEEXTENSION_WITHDOT already exists in //\${server}/\${msshare}\${mssubdir}\" >> /var/tmp/scriptd.out 113 | umount \${mountp} 114 | rm -f ${fname_noext}BACKUPFILENAMEEXTENSION_WITHDOT* 115 | exit 1 116 | else 117 | echo \"DEBUG: File ${fname_noext}BACKUPFILENAMEEXTENSION_WITHDOT does not already exist in //\${server}/\${msshare}\${mssubdir} (continuing...)\" >> /var/tmp/scriptd.out 118 | fi 119 | else 120 | echo \"DEBUG: Destination SMB mount contains no BACKUPFILENAMEEXTENSION_NODOT files (continuing...)\" >> /var/tmp/scriptd.out 121 | fi 122 | cp ${fname_noext}BACKUPFILENAMEEXTENSION_WITHDOT* \${mountp} 123 | rm -f ${fname_noext}BACKUPFILENAMEEXTENSION_WITHDOT* 124 | 125 | if \[ \"PRUNINGMODE\" \!= \"Disabled\" \]; then 126 | 127 | files_tokeep=\$(ls -t \${mountp}/*PRUNINGSUFFIX.BACKUPFILENAMEEXTENSION_NODOT 2>/dev/null | head -n CONSERVE\) 128 | for current_archive_file in `ls \${mountp}/*PRUNINGSUFFIX.BACKUPFILENAMEEXTENSION_NODOT 2>/dev/null` ; do 129 | current_archive_file_basename=`basename \$current_archive_file` 130 | check_file=\$(echo \$files_tokeep | grep -w \$current_archive_file_basename) 131 | if \[ \"\$check_file\" == \"\" \] ; then 132 | rm -f \$current_archive_file 133 | fi 134 | done 135 | if \[ \"BACKUPFILENAMEEXTENSION_NODOT\" == \"scf\" \] ; then 136 | tar_files_tokeep=\$(ls -t \${mountp}/*PRUNINGSUFFIX.BACKUPFILENAMEEXTENSION_NODOT.tar 2>/dev/null | head -n CONSERVE\) 137 | for current_archive_tar_file in `ls \${mountp}/*PRUNINGSUFFIX.BACKUPFILENAMEEXTENSION_NODOT.tar 2>/dev/null` ; do 138 | current_archive_tar_file_basename=`basename \$current_archive_tar_file` 139 | check_file=\$(echo \$tar_files_tokeep | grep -w \$current_archive_tar_file_basename) 140 | if \[ \"\$check_file\" == \"\" \] ; then 141 | rm -f \$current_archive_tar_file 142 | fi 143 | done 144 | fi 145 | fi 146 | 147 | umount \${mountp} 148 | 149 | exit 0 150 | 151 | ========== 152 | LOCAL PRUNING 153 | ========== 154 | 155 | files_tokeep=\$(ls -t BACKUPDIRECTORY/*PRUNINGSUFFIX.BACKUPFILENAMEEXTENSION_NODOT 2>/dev/null | head -n CONSERVE\) 156 | for current_archive_file in `ls BACKUPDIRECTORY/*PRUNINGSUFFIX.BACKUPFILENAMEEXTENSION_NODOT 2>/dev/null` ; do 157 | current_archive_file_basename=`basename \$current_archive_file` 158 | check_file=\$(echo \$files_tokeep | grep -w \$current_archive_file_basename) 159 | if \[ \"\$check_file\" == \"\" \] ; then 160 | rm -f \$current_archive_file 161 | fi 162 | done 163 | if \[ \"BACKUPFILENAMEEXTENSION_NODOT\" == \"scf\" \] ; then 164 | tar_files_tokeep=\$(ls -t BACKUPDIRECTORY/*PRUNINGSUFFIX.BACKUPFILENAMEEXTENSION_NODOT.tar 2>/dev/null | head -n CONSERVE\) 165 | for current_archive_tar_file in `ls BACKUPDIRECTORY/*PRUNINGSUFFIX.BACKUPFILENAMEEXTENSION_NODOT.tar 2>/dev/null` ; do 166 | current_archive_tar_file_basename=`basename \$current_archive_tar_file` 167 | check_file=\$(echo \$tar_files_tokeep | grep -w \$current_archive_tar_file_basename) 168 | if \[ \"\$check_file\" == \"\" \] ; then 169 | rm -f \$current_archive_tar_file 170 | fi 171 | done 172 | fi 173 | -------------------------------------------------------------------------------- /f5.automated_backup.v3.2.0.scripts.sh: -------------------------------------------------------------------------------- 1 | ========== 2 | SCP 3 | ========== 4 | 5 | scp_function() 6 | { 7 | f5masterkey=\$(f5mku -K) 8 | username=\$(echo \"ENCRYPTEDUSERNAME\" | openssl aes-256-ecb -salt -a -A -d -k \${f5masterkey}) 9 | server=\$(echo \"ENCRYPTEDSERVER\" | openssl aes-256-ecb -salt -a -A -d -k \${f5masterkey}) 10 | directory=\$(echo \"ENCRYPTEDDIRECTORY\" | openssl aes-256-ecb -salt -a -A -d -k \${f5masterkey}) 11 | echo \"ENCRYPTEDPRIVATEKEY\" | openssl aes-256-ecb -salt -a -A -d -k \${f5masterkey} > /var/tmp/TMSHAPPNAME_scp.key 12 | 13 | chmod 600 /var/tmp/TMSHAPPNAME_scp.key 14 | scp -i /var/tmp/TMSHAPPNAME_scp.key SCPCIPHER SCPSTRICTHOSTKEYCHECKING BACKUPDIRECTORY/${fname_noext}BACKUPFILENAMEEXTENSION_WITHDOT* \${username}@\${server}:./\${directory} 2>> /var/tmp/scriptd.out 15 | scp_result=\$? 16 | rm -f /var/tmp/TMSHAPPNAME_scp.key 17 | return \$scp_result 18 | } 19 | 20 | scp_function 21 | 22 | ========== 23 | SFTP 24 | ========== 25 | 26 | sftp_function() 27 | { 28 | f5masterkey=\$(f5mku -K) 29 | username=\$(echo \"ENCRYPTEDUSERNAME\" | openssl aes-256-ecb -salt -a -A -d -k \${f5masterkey}) 30 | server=\$(echo \"ENCRYPTEDSERVER\" | openssl aes-256-ecb -salt -a -A -d -k \${f5masterkey}) 31 | directory=\$(echo \"ENCRYPTEDDIRECTORY\" | openssl aes-256-ecb -salt -a -A -d -k \${f5masterkey}) 32 | echo \"ENCRYPTEDPRIVATEKEY\" | openssl aes-256-ecb -salt -a -A -d -k \${f5masterkey} > /var/tmp/TMSHAPPNAME_sftp.key 33 | 34 | chmod 600 /var/tmp/TMSHAPPNAME_sftp.key 35 | echo put BACKUPDIRECTORY/${fname_noext}BACKUPFILENAMEEXTENSION_WITHDOT* | sftp -b- -i /var/tmp/TMSHAPPNAME_sftp.key SFTPCIPHER SFTPSTRICTHOSTKEYCHECKING \${username}@\${server}:./\${directory} 2>> /var/tmp/scriptd.out 36 | sftp_result=\$? 37 | rm -f /var/tmp/TMSHAPPNAME_sftp.key 38 | return \$sftp_result 39 | } 40 | 41 | sftp_function 42 | 43 | ========== 44 | FTP 45 | ========== 46 | 47 | ftp_function() 48 | { 49 | f5masterkey=\$(f5mku -K) 50 | username=\$(echo \"ENCRYPTEDUSERNAME\" | openssl aes-256-ecb -salt -a -A -d -k \${f5masterkey}) 51 | password=\$(echo \"ENCRYPTEDPASSWORD\" | openssl aes-256-ecb -salt -a -A -d -k \${f5masterkey}) 52 | # Escape every character for safe submission of special characters in the password 53 | password_escaped=\$(echo \${password} | sed \'s/./\\\\\\&/g\') 54 | server=\$(echo \"ENCRYPTEDSERVER\" | openssl aes-256-ecb -salt -a -A -d -k \${f5masterkey}) 55 | directory=\$(echo \"ENCRYPTEDDIRECTORY\" | openssl aes-256-ecb -salt -a -A -d -k \${f5masterkey}) 56 | 57 | if \[ \"BACKUPFILENAMEEXTENSION_NODOT\" == \"scf\" \] 58 | then 59 | ftp_return=\$(ftp -n \${server} << END_FTP 60 | quote USER \${username} 61 | quote PASS \${password_escaped} 62 | binary 63 | put BACKUPDIRECTORY/${fname_noext}BACKUPFILENAMEEXTENSION_WITHDOT \${directory}/${fname_noext}BACKUPFILENAMEEXTENSION_WITHDOT 64 | put BACKUPDIRECTORY/${fname_noext}BACKUPFILENAMEEXTENSION_WITHDOT.tar \${directory}/${fname_noext}BACKUPFILENAMEEXTENSION_WITHDOT.tar 65 | quit 66 | END_FTP 67 | ) 68 | else 69 | ftp_return=\$(ftp -n \${server} << END_FTP 70 | quote USER \${username} 71 | quote PASS \${password_escaped} 72 | binary 73 | put BACKUPDIRECTORY/${fname_noext}BACKUPFILENAMEEXTENSION_WITHDOT \${directory}/${fname_noext}BACKUPFILENAMEEXTENSION_WITHDOT 74 | quit 75 | END_FTP 76 | ) 77 | fi 78 | 79 | if \[ \"\$ftp_return\" == \"\" \] 80 | then 81 | return 0 82 | else 83 | echo \"\$ftp_return\" >> /var/tmp/scriptd.out 84 | return 1 85 | fi 86 | } 87 | 88 | ftp_function 89 | 90 | ========== 91 | SMB/CIFS 92 | ========== 93 | 94 | \#\!/bin/sh 95 | f5masterkey=\$(f5mku -K) 96 | username=\$(echo \"ENCRYPTEDUSERNAME\" | openssl aes-256-ecb -salt -a -A -d -k \${f5masterkey}) 97 | password=\$(echo \"ENCRYPTEDPASSWORD\" | openssl aes-256-ecb -salt -a -A -d -k \${f5masterkey}) 98 | msdomain=\$(echo \"ENCRYPTEDMSDOMAIN\" | openssl aes-256-ecb -salt -a -A -d -k \${f5masterkey}) 99 | server=\$(echo \"ENCRYPTEDSERVER\" | openssl aes-256-ecb -salt -a -A -d -k \${f5masterkey}) 100 | msshare=\$(echo \"ENCRYPTEDMSSHARE\" | openssl aes-256-ecb -salt -a -A -d -k \${f5masterkey}) 101 | mssubdir=\$(echo \"ENCRYPTEDMSSUBDIR\" | openssl aes-256-ecb -salt -a -A -d -k \${f5masterkey}) 102 | mountp=\$(echo \"ENCRYPTEDMOUNTP\" | openssl aes-256-ecb -salt -a -A -d -k \${f5masterkey}) 103 | cd BACKUPDIRECTORY 104 | if \[ \! -d \${mountp} \] 105 | then 106 | mkdir -p \${mountp} 107 | if \[ \$? -ne 0 \] 108 | then 109 | rm -f ${fname_noext}BACKUPFILENAMEEXTENSION_WITHDOT* 110 | exit 1 111 | fi 112 | fi 113 | \# The password must be surrounded by two single-quotes to successfully handle special characters. Still does not support comma, single-quote, and double-quote. 114 | mount -t cifs //\${server}/\${msshare}\${mssubdir} \${mountp} -o user=\${username}%\'\'\${password}\'\',domain=\${msdomain} 2>> /var/tmp/scriptd.out 115 | if \[ \$? -ne 0 \] 116 | then 117 | echo \"DEBUG: Failed to mount //\${server}/\${msshare}\${mssubdir}\ to \${mountp}\" >> /var/tmp/scriptd.out 118 | rm -f ${fname_noext}BACKUPFILENAMEEXTENSION_WITHDOT* 119 | exit 1 120 | else 121 | echo \"DEBUG: Successfully mounted //\${server}/\${msshare}\${mssubdir}\ to \${mountp}\" >> /var/tmp/scriptd.out 122 | fi 123 | 124 | latestFileOnSMB=\$(ls -t \${mountp}/\*.BACKUPFILENAMEEXTENSION_NODOT 2>/dev/null| head -n 1 2>/dev/null) 125 | echo \"DEBUG: Latest BACKUPFILENAMEEXTENSION_NODOT file found on SMB mount: \$latestFileOnSMB\" >> /var/tmp/scriptd.out 126 | 127 | if \[ \"X\"\${latestFileOnSMB} \!= \"X\" \] 128 | then 129 | sum1=\$(md5sum ${fname_noext}BACKUPFILENAMEEXTENSION_WITHDOT | awk '{print \$1}') 130 | sum2=\$(md5sum \${latestFileOnSMB} | awk \'{print \$1}\') 131 | if \[ \${sum1} == \${sum2} \] 132 | then 133 | echo \"ERROR: File ${fname_noext}BACKUPFILENAMEEXTENSION_WITHDOT already exists in //\${server}/\${msshare}\${mssubdir}\" >> /var/tmp/scriptd.out 134 | umount \${mountp} 135 | rm -f ${fname_noext}BACKUPFILENAMEEXTENSION_WITHDOT* 136 | exit 1 137 | else 138 | echo \"DEBUG: File ${fname_noext}BACKUPFILENAMEEXTENSION_WITHDOT does not already exist in //\${server}/\${msshare}\${mssubdir} (continuing...)\" >> /var/tmp/scriptd.out 139 | fi 140 | else 141 | echo \"DEBUG: Destination SMB mount contains no BACKUPFILENAMEEXTENSION_NODOT files (continuing...)\" >> /var/tmp/scriptd.out 142 | fi 143 | cp ${fname_noext}BACKUPFILENAMEEXTENSION_WITHDOT* \${mountp} 144 | rm -f ${fname_noext}BACKUPFILENAMEEXTENSION_WITHDOT* 145 | 146 | if \[ \"PRUNINGMODE\" \!= \"Disabled\" \]; then 147 | 148 | files_tokeep=\$(ls -t \${mountp}/*PRUNINGSUFFIX.BACKUPFILENAMEEXTENSION_NODOT 2>/dev/null | head -n CONSERVE\) 149 | for current_archive_file in `ls \${mountp}/*PRUNINGSUFFIX.BACKUPFILENAMEEXTENSION_NODOT 2>/dev/null` ; do 150 | current_archive_file_basename=`basename \$current_archive_file` 151 | check_file=\$(echo \$files_tokeep | grep -w \$current_archive_file_basename) 152 | if \[ \"\$check_file\" == \"\" \] ; then 153 | rm -f \$current_archive_file 154 | fi 155 | done 156 | if \[ \"BACKUPFILENAMEEXTENSION_NODOT\" == \"scf\" \] ; then 157 | tar_files_tokeep=\$(ls -t \${mountp}/*PRUNINGSUFFIX.BACKUPFILENAMEEXTENSION_NODOT.tar 2>/dev/null | head -n CONSERVE\) 158 | for current_archive_tar_file in `ls \${mountp}/*PRUNINGSUFFIX.BACKUPFILENAMEEXTENSION_NODOT.tar 2>/dev/null` ; do 159 | current_archive_tar_file_basename=`basename \$current_archive_tar_file` 160 | check_file=\$(echo \$tar_files_tokeep | grep -w \$current_archive_tar_file_basename) 161 | if \[ \"\$check_file\" == \"\" \] ; then 162 | rm -f \$current_archive_tar_file 163 | fi 164 | done 165 | fi 166 | fi 167 | 168 | umount \${mountp} 169 | 170 | exit 0 171 | 172 | ========== 173 | LOCAL PRUNING 174 | ========== 175 | 176 | files_tokeep=\$(ls -t BACKUPDIRECTORY/*PRUNINGSUFFIX.BACKUPFILENAMEEXTENSION_NODOT 2>/dev/null | head -n CONSERVE\) 177 | for current_archive_file in `ls BACKUPDIRECTORY/*PRUNINGSUFFIX.BACKUPFILENAMEEXTENSION_NODOT 2>/dev/null` ; do 178 | current_archive_file_basename=`basename \$current_archive_file` 179 | check_file=\$(echo \$files_tokeep | grep -w \$current_archive_file_basename) 180 | if \[ \"\$check_file\" == \"\" \] ; then 181 | rm -f \$current_archive_file 182 | fi 183 | done 184 | if \[ \"BACKUPFILENAMEEXTENSION_NODOT\" == \"scf\" \] ; then 185 | tar_files_tokeep=\$(ls -t BACKUPDIRECTORY/*PRUNINGSUFFIX.BACKUPFILENAMEEXTENSION_NODOT.tar 2>/dev/null | head -n CONSERVE\) 186 | for current_archive_tar_file in `ls BACKUPDIRECTORY/*PRUNINGSUFFIX.BACKUPFILENAMEEXTENSION_NODOT.tar 2>/dev/null` ; do 187 | current_archive_tar_file_basename=`basename \$current_archive_tar_file` 188 | check_file=\$(echo \$tar_files_tokeep | grep -w \$current_archive_tar_file_basename) 189 | if \[ \"\$check_file\" == \"\" \] ; then 190 | rm -f \$current_archive_tar_file 191 | fi 192 | done 193 | fi 194 | --------------------------------------------------------------------------------