Category: Technology
What Would You Do Differently If You Were To Build Your App Again?
Most app developers start with one but have so many ideas they end up developing multiple apps. After
you’ve built your first app, it’s time to evaluate the process and figure out what you might do differently.
Let’s look at a few things to consider before you decide to develop your next app.
Fewer Features
Did you include too many features in your first app? After launching, maybe you found out users felt
overwhelmed by the features or simply didn’t use most of them.
While you want your new app to be the coolest with the best features, too many features can cause
issues. It’s better to start off with an app prototype with the most important features and add features
as users make suggestions.
Investing too much Money
Maybe your first app cost you a large sum of money and you really don’t want to go down that road
again. With our app prototype service, you can keep the initial investment lower and fine-tune your app
before investing a larger amount of cash.
Focus on the User More
Did you spend months upon months with tunnel vision the first time around? You treated your app like
a new baby joining your family and wanted it to the absolutely perfect. It turned out to be your vision
and launched just as you wanted, but the users barely factored into the equation.
Getting as much input from test groups, user groups, early adopters, early investors, and others helps to
make your app stronger. Our team will help you with your next app by providing an app prototype
service. In just two weeks, we deliver a working app to your phone, which you can use for testing with
users and presenting to investors.
Outsource the Work
Did you have your app developed in-house? This can get rather expensive since you pay for the people
working on your app day in and day out.
When you outsource the work to a development company, you pay when you need them, not when
they show up to work.
When you hire Matraex, we charge a flat fee for our app prototype service. It doesn’t matter how many
developers we have on the project or the amount of time it takes them each day, the fee is the same.
Outsourcing your app development can help you avoid unnecessary expenses. The right developers will
already know the programming language you need and will likely work faster than an in-house team.
Plus, ongoing expenses only occur when you need work done instead of when employees clock in for
the day.
If you’re ready to develop another app, our app prototype service offers the right solution for you. Why
should you have to fork over tens of thousands of dollars and wait months to see your app in action? Let
us create an app prototype for you in just two weeks!
Moving PHP sites to php 7.2 – undefined constants used as a string
PHP7.2 and above will no longer allow Undefined Constants
According to the “Promote the error level of undefined constants” section of the PHP 7.2 Backwards Incompatible Changes Document
Unqualified references to undefined constants will now generate anE_WARNING
(instead of anE_NOTICE
). In the next major version of PHP, they will generate Error exceptions.
There have been many changes to PHP over its many versions – For Matraex’s use of PHP, each version has been mostly compatible with the previous one with only minor changes, until a major decision affected one of the ways we deliberately used what we once called a “Feature” of PHP. (For a full list of incompatible changes look at the Backwards Incompatible Changes sections in the PHP Appendices )
On March 5th, 2017, Rowan Collins proposed to deprecate bareword strings. In PHP 7.2 the messages throw an E_WARNING message and in PHP 8.0 it will through an E_ERROR.
PHP has always been a loosely typed language which allows flexibility in many ways, And we had used this flexibility in order write code in a ways that we belive made it more legible, maintainable and supportable within our coding style. With this new change, hundreds of thousands of lines of code will need to be rewrittend before we can put it on a 7.2 or above server, keys may be difficult to search, we will have inconsistencies in usage of keys depending on whether they are inside or out side of quotes.
Take this one example where lines 1, 3 and 4 below would work, but line 2 would throw a warning in 7.2 and would through an error in 8.0.
- echo “Hello, $user[firstname],”;
- echo “Hello, “.$user[firstname].”,”;
- echo “Hello, “.$user[‘firstname’].”,”;
- echo “Hello, “.$user[“firstname”].”,”;
Matraex would have previously preferred to use methods 1 and then 2, as they require fewer quotes and a search in our IDE of ‘user[first’ would have highlighted both uses.
Mr Collins did evaluate both sides of the decision and wrote a bit about it. He described that “The value of keeping the current behaviour would be for programs written to deliberately take advantage of it”, however he really dismisses that value and gave a stronger argument undefined constants can “mask serious bugs”.
I agree with each of the arguments and our 7.2 scripts will all comply with this new syntax requirement. However, I disagree with the way the solution was indiscriminately executed. A more considerate solution would have been to create a configuration option in PHP to control the requirement and allow developers and system administrators to continue to ‘deliberately’ use ‘undefined constants’. This option would also allow existing stable programs to continue to take advantage of the other features of PHP >=7.2 without a significant refactor. Perhaps the Impact section of the article could attempted to get more feedback from users that had deliberately made heavy investment in this feature.
To be more direct here is my request: PHP developers, please create / allow a configuration option in PHP which will allow undefined constants to be used as strings.
Changing existing code across the 10 + years of PHP projects will take thousands of hours to modify and test, and that is just the projects that still exist. This is a barrier to upgrading to PHP 8.0.
Arguments for a configuration option
- Millions of lines of code which deliberately use undefined constants as string (more likely billions or trillions – I probably have close to one million myself overtime)
- My random belief: PHP should enforce “standards” on those that want or need them, and allow experience users to explicitly choose to ignore them.
- The configuration option would be disabled by default to address all of the problems mentioned in ‘the problem’ section of the article
Dealing with undefined constant warnings
Now we get to more technical area where I document some of the methods we have used to find code that needs to be updated for PHP 7.2 code.
1) Use grep to find all uses of the code
This code finds ALL uses of lower case strings without quotes – because our standards do require constants to be in upper case
grep -Rne ‘\$[A-Z\_a-z]*\[[A-Za-Z\_]\{1,\}\]’ *.php
2) Suppress E_WARNING messages
This is a bad idea, while it will certainly make it so that your code continues to work in 7.2, it will not fix it going into 8.0, and this WILL mask other issues that you do need to know about.
If you want to learn mroe about this, take a look at this discussion about it on Stack Overflow. Definitely read the comments about hiding warnings to get a better feel for it.
3) Create PHP configuration options to make provisions for undefined constants
These options would require the good work of a C developer that works on the PHP source. Some of these ideas may just work as described, they really are just a good start (or continuation) of a discussion for features which could be implemented. I don’t have a ‘bounty’ system but if you are interested in creating any of these options, or would like to group together to coordinate it, please contact me.
- undefined_constants_string_level – Have a PHP directive which declares what E_ level all undefined constant warnings should – default in 8.0 can be E_ERROR
- undefined_constants_string_lowercase – Allow users to configure options which would allow only lowercase (or mixed case) constants as strings – which would allow / reserve upper case for use as constants.
- undefined_constants_string_superglobal – Allow undefined constants to be used when attempting to reference any key to a super global array (such as $_POST[mykey] or S_SERVER[HTTP_HOST]);
COMMANDDUMP: postfix – explore and fix spam clogged mailq at the command line
- SystemA is a postfix mailserver
- SystemA receives all email messages sent to @domain.com
- All @domain.com messages are forwarded to a Gmail Account remote.user@gmail.com. (a catchall alias)
- when spammers saturate @domain.com gmail starts defering emails and the server becomes plugged waiting to forward the emails
450-4.2.1
The user you are trying to contact is receiving mail at a rate that prevents additional messages from being delivered. Please resend your message at a later time. If the user is able to receive mail at that time, your message will be delivered.
List the email addresses that were originally sent to with the number of times each.
ServerA>for fl in `mailq|grep remote.user@gmail.com -B4| awk '$1 ~ /^[A-Z0-9]+$/{print $1}' `; do grep original_recipient "/var/spool/postfix/defer/${fl::1}/$fl" ; done|awk -F= '{print $NF}'|sort|uniq -c | sort -n
Delete from the mail queue all email messages sent to a specific user
ServerA>for fl in `mailq|grep remote.user@gmail.com -B4| awk '$1 ~ /^[A-Z0-9]+$/{print $1}'`; do grep original_recipient=honeypot@domain.com -l "/var/spool/postfix/defer/${fl::1}/$fl" ; done|awk -F/ '{print "postsuper -d "$NF}'|bash ServerA>#OR ServerA>grep original_recipient=original_recipient=honeypot@domain.com /var/spool/postfix/defer/ -rl|awk -F/ '{print "postsuper -d "$NF}'
Delete all mail messages from ‘Maria*’
mailq |awk '$1 ~ /^[A-Z0-9]+$/'|awk '$NF ~/^Maria/{print $0}'|awk '{print "postsuper -d "$1}'|bash
Proftpd PassivePorts Requirements (or Not Working)
After an exhaustive research session attempting to enabled Passive FTP on a Proftpd server I found and am now documenting this issue.
PassivePorts is a directive in Proftpd.conf to configure proftpd to use a specific set of ports for Passive FTP – You would the allow these ports through your firewall to your server.
The documentation on the full configuration and reason that you would use Passive vs Active FTP, and how to set it up on your server and firewall are beyond the scope of this document but I a couple of links that might get you there are here.
- http://proftpd.org/docs/directives/linked/config_ref_PassivePorts.html
- https://ubuntuforums.org/showthread.php?t=39566
- http://matrafox.info/proftpd-passive-port-not-working.html
- http://slacksite.com/other/ftp.html
In my first attempts I was attempting to use the port range between 60000 and 65535, the firewall ports were forwarded, and things did not work
- PassivePorts 60000 65535
So I had to dig in and find the details of why not, I enabled debugging on filezilla and ran at the command line in order to try and see what was happening
- proftpd -n -d30
I found a post somewhere that explained how I could read the response to the PASV command,
- Entering Passive Mode (172,31,10,46,148,107)
These last two octets in the response are the port number that is to be used here is how you calculate it (148*256 +107)=37995. Even though I had the server setup to use PassivePorts 60000 – 65535 it was still attempting to use 37995. Once I figured out how to confirm which port was being sent, I realized that the issue was not a firewall or other problem, but rather something in the system.
I happened across a Slacksite article which helped me find this in the Proftpd Document
PassivePorts restricts the range of ports from which the server will select when sent the PASV command from a client. The server will randomly choose a number from within the specified range until an open port is found. Should no open ports be found within the given range, the server will default to a normal kernel-assigned port, and a message logged.
In my research I was unable to find a message logged so I dont believe that a message shows anywhere, however this article helped me realize that there may be some issue on my system which was preventing ports 60000 to 65535 to be available and I started playing with the system
- 60000-61000 and 59000-60000 had no effect the system was still assigning ports within the 30000 to 40000 range.
- 50000 to 51000 had the same effect
So I tried some entries within the 30000 and 40000 and I found I could consistently control the ports if I used any range between 30000 and 40000
- PassivePorts 30000 32000 – gave me 31456, 31245, 30511, etc
- PassivePorts 32000 34000 – gave me 33098, 32734, 33516, etc
- etc
From this I figured out that I can only control the ports on this system in a range lower than the ones I was originally attempting
I did more research and found that there is a sysctl variable that shows the local anonymous port range
- sysctl -a|grep ip_local_port_range
On my system for some reason this was set to
- net.ipv4.ip_local_port_range = 32768 48000
I attempted setting this to a higher number
- sysctl -w net.ipv4.ip_local_port_range=”32768 65535″
However this did not change the way the proftpd allocated the ports only the lower range was available. Perhaps I could have set the variabl in sysctl.conf and restarted, but I stopped my investigation here. Instead I changed the firewall rules to allow port 32000 to 34000 through and I stuck with the configuration
- PassivePorts 32000 34000
What I learned from this was:
PassivePorts only suggests that your system use range of ports you specify, If that range is not available the system quietly selects a port outside the range you specified, If you have problems with your FTP hanging at MLSD check your logs to verify which PORT has been assigned. using the calculation (5th octet *256 + 6th octet).
Using MPT-Status for RAID Monitoring in a Poweredge C6100 with Perc 6
Using MPT-Status for RAID Monitoring in a Poweredge C6100 with Perc 6
This post outlines the steps needed to get a CLI report of the conditions of your RAIDs in a Poweredge C6100 with a PERC 6/i RAID Controller.
Verify your controller type:
cat /proc/scsi/mptsas/0
ioc0: LSISAS1068E B3, FwRev=011b0000h, Ports=1, MaxQ=277
Download the following packages:
daemonize-1.5.6-1.el5.i386.rpm mpt-status-1.2.0-3.el5.centos.i386.rpm lsscsi-0.17-3.el5.i386.rpm
http://dl.nux.ro/utils/mpt-status/mpt-status-1.2.0-3.el5.centos.i386.rpm
http://dl.nux.ro/utils/mpt-status/daemonize-1.5.6-1.el5.i386.rpm
http://mirror.centos.org/centos/5/os/i386/CentOS/lsscsi-0.17-3.el5.i386.rpm
Install mtp-status:
rpm -ivh mpt-status-1.2.0-3.el5.centos.i386.rpm daemonize-1.5.6-1.el5.i386.rpm lsscsi-0.17-3.el5.i386.rpm
modprobe mptctl
echo mptctl >> /etc/modules
Verify your modules:
lsmod |grep mpt
mptctl 90739 0
mptsas 57560 4
mptscsih 39876 1 mptsas
mptbase 91081 3 mptctl,mptsas,mptscsih
scsi_transport_sas 27681 1 mptsas
scsi_mod 145658 7 mptctl,sg,libata,mptsas,mptscsih,scsi_transport_sas,sd_mod
run:
mpt-status or mpt-status -n -s
Also, you can use: lsscsi -l
This little script:
echo `mpt-status -n -s|awk ‘/OPTIMAL/ {print $1, “OK”}; /ONLINE/ {print $1, “OK”}; /DEGRADED/ {print $1, “FAILURE”}; /scsi/ {print $2}; /MISSING/ {print $1, “FAILURE”} ‘`
reports:
vol_id:0 OK phys_id:1 OK phys_id:0 OK 100% 100%
On a rebuild, it reports:
vol_id:0 FAILURE phys_id:2 OK phys_id:3 OK 75% 75%
Copy that script into a file called “check_raid”, and make it executable, E.G. 755
Edit nagios-statd on parcel1. Replace “sudo /customcommands/check_raid.pl -b -w1 -c1” with filename check-raid (without the switches) at line 20, and remove “sudo”
So, from this:
commandlist[‘Linux’] = (“df -P”,”who -q | grep “#””,”ps ax”,”uptime”,”free | awk ‘$1~/^Swap:/{print ($3/$2)*100}'”,”sudo /customcommands/check_raid.pl -b -w1 -c1″)
To this:
commandlist[‘Linux’] = (“df -P”,”who -q | grep “#””,”ps ax”,”uptime”,”free | awk ‘$1~/^Swap:/{print ($3/$2)*100}'”,”/customcommands/check_raid”)
Port 1040 will need to be opened in XenServer. Edit /etc/sysconfig/iptables and insert this line:
-A RH-Firewall-1-INPUT -p tcp -m tcp –dport 1040 -j ACCEPT
Restart the firewall:
service iptables restart
Output:
Flushing firewall rules: [ OK ]
Setting chains to policy ACCEPT: filter [ OK ]
Unloading iptables modules: [ OK ]
Applying iptables firewall rules: [ OK ]
Loading additional iptables modules: ip_conntrack_netbios_n[FAILED]
NOTE: The “FAILED” error above doesn’t seem to be a problemVerify that port 1040 is open:
Check the status of port 1040:
service iptables status
Output:
Table: filter
Chain INPUT (policy ACCEPT)
num target prot opt source destination
1 ACCEPT 47 — 0.0.0.0/0 0.0.0.0/0
2 RH-Firewall-1-INPUT all — 0.0.0.0/0 0.0.0.0/0
Chain FORWARD (policy ACCEPT)
num target prot opt source destination
1 RH-Firewall-1-INPUT all — 0.0.0.0/0 0.0.0.0/0
Chain OUTPUT (policy ACCEPT)
num target prot opt source destination
Chain RH-Firewall-1-INPUT (2 references)
num target prot opt source destination
1 ACCEPT all — 0.0.0.0/0 0.0.0.0/0
2 ACCEPT icmp — 0.0.0.0/0 0.0.0.0/0 icmp type 255
3 ACCEPT esp — 0.0.0.0/0 0.0.0.0/0
4 ACCEPT ah — 0.0.0.0/0 0.0.0.0/0
5 ACCEPT udp — 0.0.0.0/0 224.0.0.251 udp dpt:5353
6 ACCEPT udp — 0.0.0.0/0 0.0.0.0/0 udp dpt:631
7 ACCEPT tcp — 0.0.0.0/0 0.0.0.0/0 tcp dpt:631
8 ACCEPT tcp — 0.0.0.0/0 0.0.0.0/0 tcp dpt:1040
9 ACCEPT all — 0.0.0.0/0 0.0.0.0/0 state RELATED,ESTABLISHED
10 ACCEPT udp — 0.0.0.0/0 0.0.0.0/0 state NEW udp dpt:694
11 ACCEPT tcp — 0.0.0.0/0 0.0.0.0/0 state NEW tcp dpt:22
12 ACCEPT tcp — 0.0.0.0/0 0.0.0.0/0 state NEW tcp dpt:80
13 ACCEPT tcp — 0.0.0.0/0 0.0.0.0/0 state NEW tcp dpt:443
14 REJECT all — 0.0.0.0/0 0.0.0.0/0 reject-with icmp-host-prohibited
running “nagios-statd” opens port 1040 on Parcel1 and listens for commands to be initiated by nagios_stat on the nagios server.
On the nagios server, in a file called “remote.orig.cfg, there are commands defined using “nagios-stat”: NOTE: These are from a working server and haven’t been modified to work with mpt. Some changes may need to be made. This is just an example of the interaction between Nagios server and client
Example:
define command{
command_name check_remote_raid
command_line $USER1$/nagios-stat -w $ARG1$ -c $ARG2$ -p $ARG3$ raid $HOSTADDRESS$
}
This command defined above is used in the “services.cfg” file.
Example:
define service{
use matraex-template
host_name mtx-lilac
service_description Lilac /data Raid
check_command check_remote_raid!1!1!1040
The three files needed on the C6100 node are:
/customcommands/check_raid (contents below) -rwxr-xr-x
/customcommands/nagios-statd (contents below) -rwxr-xr-x
/etc/init.d/nagios-statd (contens below) -rwxr–r–
Creating the soft links:
ln -s /etc/init.d/nagios-statd /etc/rc.d/rc3.d/K01nagios-statd
ln -s /etc/init.d/nagios-statd /etc/rc.d/rc3.d/S99nagios-statd
The -s = soft, and -f if used, forces overwrite.
/rc3.d/ designates runlevel 3
So when you do this:
ls -lt /customcommands/nagios-statd /etc/init.d/nagios-statd /customcommands/check_raid /etc/rc.d/rc3.d/*nagios-statd
This is what you should see:
lrwxrwxrwx 1 root root 22 Mar 6 08:08 /etc/rc.d/rc3.d/K01nagios-statd -> ../init.d/nagios-statd
-rwxr-xr-x 1 root root 365 Mar 6 07:59 /customcommands/check_raid
lrwxrwxrwx 1 root root 22 Mar 6 07:52 /etc/rc.d/rc3.d/S99nagios-statd -> ../init.d/nagios-statd
-rwxr-xr-x 1 root root 649 Mar 6 07:51 /etc/init.d/nagios-statd
-rwxr-xr-x 1 root root 9468 Mar 5 12:05 /customcommands/nagios-statd
Script Files:
NOTE: Here’s a little fix that helped me out. I had originally pasted these scripts into a DOS/Windows editor (wordpad) and it added DOS-type returns to the file, resulting in an error:
-bash: ./nagios-statd: /bin/sh^M: bad interpreter: No such file or directory
If you encounter this, do this:
Open the file in vi
hit “:” to go into command mode
enter “set fileformat=unix”
then :wq to quit.
/customcommands/check_raid:
#!/bin/bash
EXECFILE=/usr/sbin/mpt-status
if [ ! -e $EXECFILE ] ; then
echo
echo “Error $EXECFILE is not installed, please install before running”
echo
echo “Usage $0”;
echo
exit 10
fi
echo `$EXECFILE -n -s|awk ‘/OPTIMAL/ {print $1, “OK”}; /ONLINE/ {print $1, “OK”}; /DEGRADED/ {print $1, “FAILURE”}; /scsi/ {print $2};
/MISSING/ {print $1, “FAILURE”} ‘`
/customcommands/nagios_statd
#!/usr/bin/python
import getopt, os, sys, signal, socket, SocketServer
class Functions:
“Contains a set of methods for gathering data from the server.”
def __init__(self):
self.nagios_statd_version = 3.09
# As of right now, the commands are for df, who, proc, uptime, and swap.
commandlist = {}
commandlist[‘AIX’] = (“df -Ik”,”who | wc -l”,”ps ax”,”uptime”,”lsps -sl | grep -v Paging | awk ‘{print $2}’ | cut -f1 -d%”)
commandlist[‘BSD/OS’] = (“df”,”who | wc -l”,”ps -ax”,”uptime”,None)
commandlist[‘CYGWIN_NT-5.0’] = (“df -P”,None,”ps -s -W | awk ‘{printf(“%6s%6s%3s%6s%sn”,$1,$2,” S”,” 0:00″,substr($0,22))}'”,None,None)
commandlist[‘CYGWIN_NT-5.1’] = commandlist[‘CYGWIN_NT-5.0’]
commandlist[‘FreeBSD’] = (“df -k”,”who | wc -l”,”ps ax”,”uptime”,”swapinfo | awk ‘$1!~/^Device/{print $5}'”)
commandlist[‘HP-UX’] = (“bdf -l”,”who -q | grep “#””,”ps -el”,”uptime”,None)
commandlist[‘IRIX’] = (“df -kP”,”who -q | grep “#””,”ps -e -o “pid tty state time comm””,”/usr/bsd/uptime”,None)
commandlist[‘IRIX64’] = commandlist[‘IRIX’]
commandlist[‘Linux’] = (“df -P”,”who -q | grep “#””,”ps ax”,”uptime”,”free | awk ‘$1~/^Swap:/{print ($3/$2)*100}'”,”/customcommands/check_raid”)
commandlist[‘NetBSD’] = (“df -k”,”who | wc -l”,”ps ax”,”uptime”,”swapctl -l | awk ‘$1!~/^Device/{print $5}'”)
commandlist[‘NEXTSTEP’] = (“df”,”who | /usr/ucb/wc -l”,”ps -ax”,”uptime”,None)
commandlist[‘OpenBSD’] = (“df -k”,”who | wc -l”,”ps -ax”,”uptime”,”swapctl -l | awk ‘$1!~/^Device/{print $5}'”)
commandlist[‘OSF1’] = (“df -P”,”who -q | grep “#””,”ps ax”,”uptime”,None)
commandlist[‘SCO-SV’] = (“df -Bk”,”who -q | grep “#””,”ps -el -o “pid tty s time args””,”uptime”,None)
commandlist[‘SunOS’] = (“df -k”,”who -q | grep “#””,”ps -e -o “pid tty s time comm””,”uptime”,”swap -s | tr -d -s -c [:digit:][:space:] | nawk ‘{print ($3/($3+$4))*100}'”)
commandlist[‘UNIXWARE2’] = (“/usr/ucb/df”,”who -q | grep “#””,”ps -el | awk ‘{printf(“%6d%9s%2s%5s %sn”,$5,substr($0, 61, 8),$2,substr($0,69,5),substr($0,75))}”,”echo `uptime`, load average: 0.00, `sar | awk ‘{oldidle=idle;idle=$5} END {print 100-oldidle}’`,0.00″,None)
# Now to make commandlist with the correct one for your OS.
try:
self.commandlist = commandlist[os.uname()[0]]
except KeyError:
print “Your platform isn’t supported by nagios-statd – exiting.”
sys.exit(3)
# Below are the functions that the client can call.
def disk(self):
return self.__run(0)
def proc(self):
return self.__run(2)
def swap(self):
return self.__run(4)
def uptime(self):
return self.__run(3)
def user(self):
return self.__run(1)
def raid(self):
return self.__run(5)
def version(self):
i = “nagios-statd ” + str(self.nagios_statd_version)
return i
def __run(self,cmdnum):
# Unmask SIGCHLD so popen can detect the return status (temporarily)
signal.signal(signal.SIGCHLD, signal.SIG_DFL)
outputfh = os.popen(self.commandlist[cmdnum])
output = outputfh.read()
returnvalue = outputfh.close()
signal.signal(signal.SIGCHLD, signal.SIG_IGN)
if (returnvalue):
return “ERROR %s ” % output
else:
return output
class NagiosStatd(SocketServer.StreamRequestHandler):
“Handles connection initialization and data transfer (as daemon)”
def handle(self):
# Check to see if user is allowed
if self.__notallowedhost():
self.wfile.write(self.error)
return 1
if not hasattr(self,”generichandler”):
self.generichandler = GenericHandler(self.rfile,self.wfile)
self.generichandler.run()
def __notallowedhost(self):
“Compares list of allowed users to client’s IP address.”
if hasattr(self.server,”allowedhosts”) == 0:
return 0
for i in self.server.allowedhosts:
if i == self.client_address[0]: # Address is in list
return 0
try: # Do an IP lookup of host in blocked list
i_ip = socket.gethostbyname(i)
except:
self.error = “ERROR DNS lookup of blocked host “%s” failed. Denying by default.” % i
return 1
if i_ip != i: # If address in list isn’t an IP
if socket.getfqdn(i) == socket.getfqdn(self.client_address[0]):
return 0
self.error = “ERROR Client is not among hosts allowed to connect.”
return 1
class GenericHandler:
def __init__(self,rfile=sys.stdin,wfile=sys.stdout):
# Create functions object
self.functions = Functions()
self.rfile = rfile
self.wfile = wfile
def run(self):
# Get the request from the client
line = self.rfile.readline()
line = line.strip()
# Check for appropriate requests from client
if len(line) == 0:
self.wfile.write(“ERROR No function requested from client.”)
return 1
# Call the appropriate function
try:
output = getattr(self.functions,line)()
except AttributeError:
error = “ERROR Function “” + line + “” does not exist.”
self.wfile.write(error)
return 1
except TypeError:
error = “ERROR Function “” + line + “” not supported on this platform.”
self.wfile.write(error)
return 1
# Send output
if output.isspace():
error = “ERROR Function “” + line + “” returned no information.”
self.wfile.write(error)
return 1
elif output == “ERROR”:
error = “ERROR Function “” + line + “” exited abnormally.”
self.wfile.write(error)
else:
for line in output:
self.wfile.write(line)
class ReUsingServer (SocketServer.ForkingTCPServer):
allow_reuse_address = True
class Initialization:
“Methods for interacting with user – initial code entry point.”
def __init__(self):
self.port = 1040
self.ip = ”
# Run this through Functions initially, to make sure the platform is supported.
i = Functions()
del(i)
def getoptions(self):
“Parses command line”
try:
opts, args = getopt.getopt(sys.argv[1:], “a:b:ip:P:Vh”, [“allowedhosts=”,”bindto=”,”inetd”,”port=”,”pid=”,”version”,”help”])
except getopt.GetoptError, (msg, opt):
print sys.argv[0] + “: ” + msg
print “Try ‘” + sys.argv[0] + ” –help’ for more information.”
sys.exit(3)
for option,value in opts:
if option in (“-a”,”–allowedhosts”):
value = value.replace(” “,””)
self.allowedhosts = value.split(“,”)
elif option in (“-b”,”–bindto”):
self.ip = value
elif option in (“-i”,”–inetd”):
self.runfrominetd = 1
elif option in (“-p”,”–port”):
self.port = int(value)
elif option in (“-P”,”–pid”):
self.pidfile = value
elif option in (“-V”,”–version”):
self.version()
sys.exit(3)
elif option in (“-h”,”–help”):
self.usage()
def main(self):
# Retrieve command line options
self.getoptions()
# Just splat to stdout if we’re running under inetd
if hasattr(self,”runfrominetd”):
server = GenericHandler()
server.run()
sys.exit(0)
# Check to see if the port is available
try:
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
s.bind((self.ip, self.port))
s.close()
del(s)
except socket.error, (errno, msg):
print “Unable to bind to port %s: %s – exiting.” % (self.port, msg)
sys.exit(2)
# Detach from terminal
if os.fork() == 0:
# Make this the controlling process
os.setsid()
# Be polite and chdir to /
os.chdir(‘/’)
# Try to close all open filehandles
for i in range(0,256):
try: os.close(i)
except: pass
# Redirect the offending filehandles
sys.stdin = open(‘/dev/null’,’r’)
sys.stdout = open(‘/dev/null’,’w’)
sys.stderr = open(‘/dev/null’,’w’)
# Set the path
os.environ[“PATH”] = “/bin:/usr/bin:/usr/local/bin:/usr/sbin”
# Reap children automatically
signal.signal(signal.SIGCHLD, signal.SIG_IGN)
# Save pid if user requested it
if hasattr(self,”pidfile”):
self.savepid(self.pidfile)
# Create a forking TCP/IP server and start processing
server = ReUsingServer((self.ip,self.port),NagiosStatd)
if hasattr(self,”allowedhosts”):
server.allowedhosts = self.allowedhosts
server.serve_forever()
# Get rid of the parent
else:
sys.exit(0)
def savepid(self,file):
try:
fh = open(file,”w”)
fh.write(str(os.getpid()))
fh.close()
except:
print “Unable to save PID file – exiting.”
sys.exit(2)
def usage(self):
print “Usage: ” + sys.argv[0] + ” [OPTION]”
print “nagios-statd daemon – remote UNIX system monitoring tool for Nagios.n”
print “-a, –allowedhosts=HOSTS Comma delimited list of IPs/hosts allowed to connect.”
print “-b, –bindto=IP IP address for the daemon to bind to.”
print “-i, –inetd Run from inetd.”
print “-p, –port=PORT Port to listen on.”
print “-P, –pid=FILE Save pid to FILE.”
print “-V, –version Output version information and exit.”
print ” -h, –help Print this help and exit.”
sys.exit(3)
def version(self):
i = Functions()
print “nagios-statd %.2f” % i.nagios_statd_version
print “os.uname()[0] = %s ” % os.uname()[0]
print “Written by Nick Reinkingn”
print “Copyright (C) 2002 Nick Reinking”
print “This is free software. There is NO warranty; not even for MERCHANTABILITY or”
print “FITNESS FOR A PARTICULAR PURPOSE.”
print “nNagios is a trademark of Ethan Galstad.”
if __name__ == “__main__”:
# Check to see if running Python 2.x+ / needed because getfqdn() is Python 2.0+ only
if (int(sys.version[0]) < 2):
print “nagios-statd requires Python version 2.0 or greater.”
sys.exit(3)
i = Initialization()
i.main()
/etc/init.d/nagios-statd:
#!/bin/sh
#
# This file should have uid root, gid sys and chmod 744
#
if [ ! -d /usr/bin ]
then # /usr not mounted
exit
fi
killproc() { # kill the named process(es)
pid=`/bin/ps -e |
/bin/grep -w $1 |
/bin/sed -e ‘s/^ *//’ -e ‘s/ .*//’`
[ “$pid” != “” ] && kill $pid
}
# Start/stop processes required for netsaint_statd server
case “$1” in
‘start’)
/customcommands/nagios-statd -a <IP of Allowed Nagios Server>,<IP of Test Workstation> -p 1040
;;
‘stop’)
killproc nagios-statd
;;
*)
echo “Usage: /etc/init.d/nagios-statd { start | stop }”
;;
esac
Testing:
As you can see in the script file above, I’ve added the IP Address of a test workstation. This will allow me to simply telnet to a node in the C6100 and execute one of the commands defined in this section of the /customcommands/nagios-statd script:
# Below are the functions that the client can call.
def disk(self):
return self.__run(0)
def proc(self):
return self.__run(2)
def swap(self):
return self.__run(4)
def uptime(self):
return self.__run(3)
def user(self):
return self.__run(1)
def raid(self):
return self.__run(5)
At your workstation, telnet to <Node IP Address> 1040
When connected, the screen will be blank.
Type “raid”. The screen won’t echo this.
When you hat enter, you should see:
vol_id:0 OK phys_id:2 OK phys_id:3 OK 100% 100%
Now you’re ready to move on to the Nagios configuration.
Matt Long
03/06/2015
Installing Veeam Backup for VMWare
Installing Veeam Backup for VMWare
This is a “From Scratch” implementation of Veeam backup & Replication 8.0 for VMWare.
I’ll be installing B&R (Backup & Replication) on a VM on the target server, which is running EXSi 5.5, and installing the Enterprise Management Console on a workstation.
Download Veeam B&R from Veeam’s website. You’ll have to register, and make sure you use an email address that isn’t public (e.g. gmail,yahoo, etc.) or you won’t get access to the things you’ll need. Get the B&R ISO, the license file, and the latest patch.
Check the release notes for system requirements. Here’s a helpful Installation Guide on Veeams Help Center:
http://helpcenter.veeam.com/backup/80/vsphere/index.html?install_vbr_1.html
Hardware requirements are: at least 2 cores 4GB RAM MINIMUM.
My VM has:
2 cores
8GB RAM
100GB Hard Drive NOTE: the fully set up machine came to 38GB.
I’m installing on a Windows 7 Pro VM and found that I needed Service Pack 1,Powershell 2.0, and Internet Explorer 9 or higher. These aren’t included in the Veeam installation package. I’ve also downloaded and installed Microsoft Security Essentials.
The filenames for these updates are:
Windows6.1-KB2819745-x64-MultiPkg.exe, IE11-Windows6.1-x64-en-us.exe, and windows6.1-KB976932-X64.exe
After meeting all of the prerequisites I began the installation. choosing the default settings and letting the installation add the required software bundled with it.
Install any patches issued by veeam.
Setting up Nagios monitoring on Windows 2003r2 through a Firewall
Setting up Nagios monitoring on Windows 2003r2 through a Firewall
Download nrpe_nt, currently nrpe_nt.0.8b-bin.zip Extract to the root of c: on the Target Windows Machine. You should have a directory called c:nrpe, that contains a sub-directory called bin. Download the plugins, currently nrpe_nt_plugins.zip. Unzip this file and place the executables in a directory called c:nrpepluginsbin Change to the c:nrpebin directory, edit the nrpe.cfg file to look like this: server_port=<port# you'll use for this particular Target Machine> server_address=<This Target Machine's IP Address> allowed_hosts=<The IP Address of your Nagios Server> debug=1 command_timeout=30 loglevel=7 command[check_cmd]=C:nrpebintest.cmd command[check_cpuload]=C:nrpepluginsbincpuload_nrpe_nt.exe 70 90 command[check_disk_c]=C:nrpepluginsbindiskspace_nrpe_nt.exe c: 70 90 command[check_disk_d]=C:nrpepluginsbindiskspace_nrpe_nt.exe d: 70 90 command[check_disk_e]=C:nrpepluginsbindiskspace_nrpe_nt.exe e: 70 90 command[check_memload]=C:nrpepluginsbinmemload_nrpe_nt.exe 70 90 open a command prompt, and: cdnrpebin nrpe_nt -i You should get a confirmation that the service was created successfully. Go to Administrative Tools > Services and start the service You can test that the client is listening on the designated port on the Windows Target Machine:
netstat -aon | findstr <port#>
Test the connection from the CLI at the nagios server: /usr/lib/nagios/plugins/check_nrpe -H <IP of the Firewall> -p 1248 MEMUSE -p <port# defined in the firewall and configured in nrpe.cfg on the target> On the Nagios Server, in the /etc/nagios3/conf.d/check_nrpe.cfg file, define a command that will use the -p switch to allow for a port # argument: define command { command_name check_nrpe_port command_line /usr/lib/nagios/plugins/check_nrpe -t20 -H $HOSTADDRESS$ -c $ARG1$ -p $ARG2$ } -c = The command executable on the Target Machine in c:nrpepluginsbin -p = the port # In the /etc/nagios3/conf.d/hosts_orig.cfg file, create your host using the ip address of the firewall. define host{ use test-host host_name test-dc1 alias test-dc1 address <IP Address of the Gateway> In the /etc/nagios3/conf.d/services.cfg file, create the services for your host using the host_name defined above and the command name you created with arguments. Set your port number for this Target Machine here, making sure the port# matches the Target Machine where you defined that port#. define service{ use test-template host_name test-dc1 service_description disk C: check_command check_nrpe_port!check_disk_c!5667 } define service{ use test-template host_name test-dc1 service_description CPU load check_command check_nrpe_port!check_cpuload!5667 } define service{ use test-template host_name test-dc1 service_description memory load check_command check_nrpe_port!check_memload!5667 } Reload nagios and check for errors. Service nagios3 reload At the firewall: Note: This example is using a Safe@Office 500P firewall, so the terminology may be different. You will need to create a service using tcp protocol and corresponding to each nrpe port number that you'll be using. In this case, I'm using 5666 through 5671. In my case, these settings were under Network > Services in the 500P configuration web interface. Create a new network object for the Nagios Server using its IP Address You'll need network objects for the Target Machines that you'll be monitoring. Create “allow and Forward” rules for each of your Target Machines using the service for the port # you assigned to that Target Machine: Service = Standard Service, The service w/correct port for you Target machine Source = Your Nagios Server Destination = “This Gateway” Forward to = Target Machine Continue by configuring your Nagios Server to monitor these new Targets. When defining the host in the hosts.cfg file for Nagios, use the firewall's gateway IP Address Matt Long 02/05/2015
Mdadm – Failed disk recovery (unreadable disk)
Mdadm – Failed disk recovery (unreadable disk)
Well,
After 9 more months I ran into a nother disk failure. (First disk failure found here https://www.matraex.com/mdadm-failed-disk-recovery/)
But this time, The system was unable to read the disk at all
#fdisk /dev/sdb
This process just hung for a few minutes. It seems I couldn’t simply run a few commands like before to remove and add the disk back to the software RAID. So I had to replace the disk. Before I went to the datacenter I ran
#mdadm /dev/md0 --remove /dev/sdb1
I physically went to our data center, found the disk that showed the failure (it was disk sdb so I ‘assumed’ it was the center disk out of three, but I was able to verify since it was not blinking from normal disk activity. I removed the disk, swapped it out for one that I had sitting their waiting for this to happen, and replaced it. Then I ran a command to make sure the disk was correctly partitioned to be able to fit into the array
#fdisk /dev/sdb
This command did not hang, but responded with cannot read disk. Darn, looks like some error happened within the OS or on the backplane that made it so a newly added disk wasn’t readable. I scheduled a restart on the server later when the server came back up, fdisk could read the disk. It looks like I had used the disk for something before, but since I had put it in my spare disk pile, I knew I could delete it and I partitioned it with one partion to match what the md was expecting (same as the old disk)
#fdisk /dev/sdb
>d 2 -deletes the old partition 2
>d 1 -deletes the old partition 1
>c -creates a new partion
>p – sets the new partion as primary
>1 – sets the new partion as number 1
>> <ENTER> – just press enter to accept the defaults starting cylinder
>> <ENTER> – just press enter to accept the defaults ending cylinder
>> w – write the partion changes to disk
>> Ctrl +c – break out of fdisk
Now the partition is ready to add back to the raid array
#mdadm /dev/md0 –add /dev/sdb1
And we can immediately see the progress
#mdadm /dev/md0 --detail /dev/md0: Version : 00.90.03 Creation Time : Wed Jul 18 00:57:18 2007 Raid Level : raid5 Array Size : 140632704 (134.12 GiB 144.01 GB) Device Size : 70316352 (67.06 GiB 72.00 GB) Raid Devices : 3 Total Devices : 3 Preferred Minor : 0 Persistence : Superblock is persistent Update Time : Sat Feb 22 10:32:01 2014 State : active, degraded, recovering Active Devices : 2 Working Devices : 3 Failed Devices : 0 Spare Devices : 1 Layout : left-symmetric Chunk Size : 64K Rebuild Status : 0% complete UUID : fe510f45:66fd464d:3035a68b:f79f8e5b Events : 0.537869 Number Major Minor RaidDevice State 0 8 1 0 active sync /dev/sda1 3 8 17 1 spare rebuilding /dev/sdb1 2 8 33 2 active sync /dev/sdc1
And then to see the progress of rebuilding
#cat /proc/mdadm Personalities : [raid1] [raid6] [raid5] [raid4] md0 : active raid5 sdb1[3] sda1[0] sdc1[2] 140632704 blocks level 5, 64k chunk, algorithm 2 [3/2] [U_U] [==============>......] recovery = 71.1% (50047872/70316352) finish=11.0min speed=30549K/sec md1 : active raid1 sda2[0] 1365440 blocks [2/1] [U_]
Wow in the time I have been blogging this, already 71 percent rebuilt!, but wait! what is this, md1 is failed? I check my monitor and what do I find but another message that shows that md1 failed with the reboot. I was so used to getting the notice saying md0 was down I did not notice that md1 did not come backup with the reboot! How can this be?
It turnd out that sdb was in use on both md1 and md0, but even through sdb could not be read at all on /dev/sdb and /dev/sdb1 failed out of the md0 array, somehow the raid subsystem had not noticed and degraded the md1 array even though the entire sdb disk was not respoding (perhaps sdb2 WAS responding back then just not sdb), who knows at this point. Maybe the errors on the old disk could have been corrected by the reboot if I had tried that before replacing the disk, but that doesn’t matter any more, All I know is that I have to repartion the sdb device in order to support both the md0 and md1 arrays.
I had to wait until sdb finished rebuilding, then remove it from md0, use fdisk to destroy the partitions, build new partitions matching sda and add the disk back to md0 and md1
MDADM – Failed disk recovery (too many disk errors)
MDADM – Failed disk recovery (too many disk errors)
This only happens once every couple of years, but occasionally a SCSI disk on one of our servers has too many errors, and is kicked out of the md array
And… we have to rebuild it. Perhaps we should replace it since it appears to be having problems, but really, the I in RAID is inexpensive (or something) so I would rather lean to being frugal with the disks and replacing them only if required.
I can never remember of the top of my head the commands to recover, so this time I am going to blog it so I can easily find it.
First step, take a look at the status of the arrays on the disk
#cat /proc/mdstat
(I don't have a copy of what the failed drive looks like since I didn't start blogging until after)
Sometimes an infrequent disk error can cause md to fail a hard drive and remove it from an array, even though the disk is fine.
That is what happened in this case, and I knew the disk was at least partially good. The disk / partition that failed was /dev/sdb1 and was part of a RAID V, on that same device another partition is part of a RAID I, that RAID I is still healthy so I knew the disk is just fine. So I am only re-adding the disk to the array so it can rebuild. If the disk has a second problem in the next few months, I will go ahead and replace it, since the issue that happened tonight is probably indicating a disk that is beginning to fail but probably still has lots of life in it.
The simple process is
#mdadm /dev/md0 --remove /dev/sdb1
This removed the faulty disk, that is when you would physically replace the disk in the machine, since I am only going to rebuild the disk I just skip that and move to the next step.
#mdadm /dev/md0 --re-add
The disk started to reload and VOILA! we are rebuilding and will be back online in a few minutes.
Now you take a look at the status of the arrays
#cat /proc/mdstat Personalities : [raid1] [raid6] [raid5] [raid4] md0 : active raid5 sdb1[3] sdc1[2] sda1[0] 140632704 blocks level 5, 64k chunk, algorithm 2 [3/2] [U_U] [=======>.............] recovery = 35.2% (24758528/70316352) finish=26.1min speed=29020K/sec md1 : active raid1 sda2[0] sdb2[1] 1365440 blocks [2/2] [UU]
In case you want to do any trouble shooting on what happened, this command is useful in looking into the logs.
#grep mdadm /var/log/syslog -A10 -B10
But this command is the one that I use to see the important events related to the failure and rebuild. As I am typing this I am just over 60% complete rebuilt which you see in the log
#grep mdadm /var/log/syslog Jun 15 21:02:02 xxxxxx mdadm: Fail event detected on md device /dev/md0, component device /dev/sdb1 Jun 15 22:03:16 xxxxxx mdadm: RebuildStarted event detected on md device /dev/md0 Jun 15 22:11:16 xxxxxx mdadm: Rebuild20 event detected on md device /dev/md0 Jun 15 22:19:16 xxxxxx mdadm: Rebuild40 event detected on md device /dev/md0 Jun 15 22:27:16 xxxxxx mdadm: Rebuild60 event detected on md device /dev/md0
You can see from the times, it took me just over an hour to respond and start the rebuild (I know, that seems too long if I were to just do this remotely, but when I got the notice, I went on site since I thought I would have to do a physical swap and I had to wait a bit while the Colo security verified my ID, and I was probably moving a little slow after some Nachos at Jalepeno’s) Once the rebuild started it took about 10 minutes per 20% of the disk to rebuild.
————————-
Update: 9 months later the disk finally gave out and I had to manually replace the disk. I blogged again:
https://www.matraex.com/mdadm-failed-d…nreadable-disk/
Great SQL Formatting Tool
Great SQL Formatting Tool
We often deal with very complex, dynamically generated SQL Statements which run from our applications.
If we need to debug them for any reason we often have to display them to the screen and then copy and paste them in to an SQL Query window. The problem is that those SQL Statements are not always formatted to be very readable. Sometimes they might even be on a single line. This requires a bunch of time going through and reformatting the sql statement, making it legible for debugging.
I have used this tool SQLinFORM several times in the past but I keep forgetting about when I dont have to use it very often.
http://www.sqlinform.com/
I just copy and paste the SQL into the window and click Format.
It does a great job formatting code quickly and even has some options for how you would like to see the output, I then select the output and paste it into my SQL Query window.
If you use it often they do have a version for sale.