Mapping /proc/meminfo to output of free command
So an example output of free is
total used free shared buffers cached
Mem: 12333980 12151544 182436 0 233128 11197680
-/+ buffers/cache: 720820 11613160
Swap: 487416 3536 483880
And /proc/meminfo
MemTotal: 12333980 kB
MemFree: 182436 kB
Buffers: 233128 kB
Cached: 11197680 kB
SwapCached: 996 kB
Active: 7296040 kB
Inactive: 4231216 kB
Active(anon): 73848 kB
Inactive(anon): 22892 kB
Active(file): 7222192 kB
Inactive(file): 4208324 kB
Unevictable: 0 kB
Mlocked: 0 kB
SwapTotal: 487416 kB
SwapFree: 483880 kB
Dirty: 268 kB
Writeback: 0 kB
AnonPages: 95640 kB
Mapped: 7686976 kB
Shmem: 292 kB
Slab: 346296 kB
SReclaimable: 335352 kB
SUnreclaim: 10944 kB
KernelStack: 1920 kB
PageTables: 23844 kB
NFS_Unstable: 0 kB
Bounce: 0 kB
WritebackTmp: 0 kB
CommitLimit: 6654404 kB
Committed_AS: 613716 kB
VmallocTotal: 34359738367 kB
VmallocUsed: 309052 kB
VmallocChunk: 34359422748 kB
HardwareCorrupted: 0 kB
HugePages_Total: 0
HugePages_Free: 0
HugePages_Rsvd: 0
HugePages_Surp: 0
Hugepagesize: 2048 kB
DirectMap4k: 10240 kB
DirectMap2M: 12572672 kB
I’ve done my best to match up the two outputs via colors. Below you will find the math used if there is any.
Total Memory
No math needed.. follow the colors
Used Memory
So for this we want to find the math used to get the used memory on the +/- buffers line. This is the true RAM used by the system.
So this math is based on output of the cat /proc/meminfo
MemTotal - (Buffers + Cached + MemFree)
So our example would be
12333980 - (182352 + 233128 + 11197680) = 720820
Free Memory
So for this we want to find the math used to get the free memory on the +/- buffers line. This is the true RAM that can be used by applications that request it. The operating system will remove data from here to give to applications on demand.
So this math is based on output of the cat /proc/meminfo
Cached + Buffers + MemFree
So our example would be
182352 + 233128 + 11197680 = 11613160
Total Swap
No math needed.. follow the colors
Used Swap
So to find out what free is outputting is pretty simple just do the math from the meminfo output
SwapTotal - SwapFree
So that would look like
487416 - 483880 = 3536
Free Swap
No math needed.. follow the colors
Varnish ACL with X-Forwarded-For Header
So I did a setup like this once
nginx -> varnish -> backend apaches
I did the nginx in front of varnish to handle SSL termination since varnish doesn’t do SSL. So the issue is you can do this for subnet checking in your varnish config
acl vpn {
"192.168.0.0"/16;
}
sub vcl_recv {
if (client.ip ~ vpn) {
# something here
}
return(pass);
}
So the issue with this is varnish thinks the client.ip is 127.0.0.1 which is correct since the connection is coming from nginx. If varnish was out in front of nginx we wouldn’t have this problem and the example above would just work. So you might be thinking why not just replace client.ip with something like req.http.x-forwarded-for and be done with it all. Well that is a string in varnish and client.ip is an object I believe so you can’t do that. So we have to do some C hacking in the config to get around this.
I found the following example a bit ago on another blog in the comments and if I remember I’ll give credit.
So we need to add the following to make it work
C{
#include <netinet/in.h>
#include <string.h>
#include <sys/socket.h>
#include <arpa/inet.h>
}C
acl vpn {
"192.168.0.0"/16;
}
sub vcl_recv {
C{
//
// This is a hack from Igor Gariev (gariev hotmail com):
// Copy IP address from "X-Forwarded-For" header
// into Varnish's client_ip structure.
// This works with Varnish 3.0.1; test with other versions
//
// Trusted "X-Forwarded-For" header is a must!
// No commas are allowed. If your load balancer something other
// than a single IP, then use a regsub() to fix it.
//
struct sockaddr_storage *client_ip_ss = VRT_r_client_ip(sp);
struct sockaddr_in *client_ip_si = (struct sockaddr_in *) client_ip_ss;
struct in_addr *client_ip_ia = &(client_ip_si->sin_addr);
char *xff_ip = VRT_GetHdr(sp, HDR_REQ, "\020X-Forwarded-For:");
if (xff_ip != NULL) {
// Copy the ip address into the struct's sin_addr.
inet_pton(AF_INET, xff_ip, client_ip_ia);
}
}C
if (client.ip ~ vpn) {
# do something here
}
return(pass);
}
Now client.ip is set with the value of x-forwarded-for
Postfix ignore catchall relayhost
Postfix has an option where you can setup a relayhost to send all mail to another mail server. It looks something like
relayhost = [mail.domain.com]:25
So that will send all mail being sent out from the server to mail.domain.com on port 25. So what happens if you want to send mail that is sent to company.com out that server and not through another relay. You would do the following in main.cf
transport_maps = hash:/etc/postfix/transport
Then your /etc/postfix/transport would look something like
company.com :
* smtp:[mail.domain.com]:25
Then you want to run
postmap /etc/postfix/transport
Then reload postfix
service postfix reload
Now all mail for company.com will send out that server while all other mail will go through mail.domain.com:25
ps aux with line wrap
File this under you learn something new every day.
Ever do a ps aux only to get something like this to happen?
xymon 26931 0.0 0.0 38944 1396 ? S 05:44 0:00 sh -c vmstat 300 2 1>/usr/lib64/xymon/client/tmp/hob
So the output of ps aux gets cut off when it hits the end of your terminal. And you have to expand your width a lot to see it. It always bothered me till I decided to read the man page.
Now I learned you can do
ps aux --width 1000
That will line wrap your output but cut the output at 1000 characters. You can also pass w’s into the command like
ps auxww
That will ignore your terminals width settings
So now we can add the following in our .bashrc or for system wide /etc/profile so we never have to remember to add a ww or –width again
alias ps='ps ww'
So that alias means you can type ps aux and it will be like your typed ps auxww
Fabric Shell
I recently wrote a quick little fabric function to create a fabric shell. This works with a stock fabric install, you just might have to change where you import it from. It is at my Github page below.
https://github.com/mzupan/fabric_shell
If you place shell.py in the same directory as fabfile.py you can use it like
from fabric.api import *
from fabric.decorators import hosts
import shell
env.hosts = [
'host1.domain.com',
'host2.domain.com'
]
@hosts('')
def cmd():
shell.shell()
Then you can use like like
$ fab cmd
[] Executing task 'cmd'
fabric::> id
[host1.domain.com] run: id
[host1.domain.com] out: uid=1020(mzupan) gid=1020(mzupan) groups=1020(mzupan)
[host1.domain.com] out:
[host2.domain.com] run: id
[host2.domain.com] out: uid=1020(mzupan) gid=1020(mzupan) groups=1020(mzupan)
[host2.domain.com] out:
fabric::> .sudo id
[host1.domain.com] sudo: id
[host1.domain.com] out: uid=0(root) gid=0(root) groups=0(root)
[host1.domain.com] out:
[host2.domain.com] sudo: id
[host2.domain.com] out: uid=0(root) gid=0(root) groups=0(root)
[host2.domain.com] out:
fabric::>
Right now any command that is issued in the fabric shell gets run on all hosts in env.hosts and if you add .sudo in front of the command it will run them as root.
Fun with Django ManyToMany Fields
This is just another reason I find Django so easy.
For example.. Say you are making a monitoring application. Now you have a bunch of servers and you have certain groups of servers. A server can belong in more then one group also. So that is pretty easy and all with Django.
Now in your template you have a few pages. One page that displays the group information like all the servers in the group and another that displays the server information and will list all the groups that server is in. So below is my basic model layout
class Group(models.Model):
parent = models.ForeignKey("Group", null=True, blank=True)
user = models.ForeignKey(User)
name = models.CharField(max_length=100)
about = models.TextField(blank=True, null=True)
created = models.DateTimeField(auto_now_add=True)
updated = models.DateTimeField(auto_now=True)
def __unicode__(self):
return self.name
class Server(models.Model):
hostname = models.CharField(max_length=300, db_index=True)
about = models.TextField(blank=True, null=True)
created = models.DateTimeField(auto_now_add=True)
updated = models.DateTimeField(auto_now=True)
groups = models.ManyToManyField(Group)
def __unicode__(self):
return self.hostname
So to get all the groups my server is a member of is pretty easy.
s = Server.objects.get(id=1)
s.groups.all()
Now to get all the servers in a group is also easy
g = Group.objects.get(id=1)
g.server_set.all()
Crontab with a random sleep
Recently ran into this problem. We had a crontab entry that looked something like this
0 0 * * * /usr/bin/sleep $((RANDOM\%90)); cmdHere
What that attempted was to run a command a random amount of seconds once midnight hit. Now running the command on console causes it to error out
$ /usr/bin/sleep $((RANDOM\%90))
-bash: RANDOM\%90: syntax error: invalid arithmetic operator (error token is "\%90")
So what you might be saying is well the \ is messing it up so remove it. Well the problem is % is a reserved character in crontab land. It pretty much means ignore everything after it so you escape it. But its not working as expected. If you remove the \ from the shell command it works just fine.
So the real answer here was use expr. Once that was in all the crontab errors went away
0 0 * * * /bin/sleep `/usr/bin/expr $RANDOM \% 90`; cmdHere
Atomic Symlink Changes
A common deploy strategy for a lot of web sites is as follows
v1.0.10
v1.0.11
v1.1.0
current -> v1.1.0
So in this directory we have three directories and one symlink. The directories contain our web application and are tagged with the source control version they were tagged with by the developers. Now its a common practice when deploying a new version to upload the new release which will be v1.1.1 and then just change the symlink to point to the new location. That really isn’t a great idea.
Sure it will work for 99.9% of your traffic but if you have a busy website it could really effect users as your do the upgrade. You are probably saying well I’m forcing the new symlink with the following command
ln -snf v1.1.1 current
Did you ever look at the system calls using the -f flag for ln does? If not lets take a look
# strace ln -snf v1.1.1 current 2>&1 | grep link
symlink("v1.1.1", "current") = -1 EEXIST (File exists)
unlink("current") = 0
symlink("v1.1.1", "current") = 0
So you can see it first tries to create the link and finds the symlink is there so it unlinks curent and makes the new symlink. The man page even says this is the case!
-f If the target file already exists, then unlink it so that the link may occur. (The -f option overrides any previous -i options.)
So how do we make this more atomic so that our users do not even notice and everyone is happy? Well its very simple.
ln -s v1.1.1 current.new && mv -Tf current.new current
That will do an atomic update. If you want to learn more about the -T flag you can find it here
It might not be 100% atomic but it’s really the best I can get right now. POSIX says its atomic so right now I’ll trust it.
Tav’s Fabric Fork Quick Start
I’ve been a big fan of the fabric project for a long time now. It has made my life very easy in the past and gets better with each new release. Well a few weeks ago I got introduced to a fork of the project by Tav. It provides many new feature additions to fabric and makes fabric a little bit better. So the best way to get it started is via the following
git clone git://github.com/tav/pylibs.git
cd pylibs
python setup.py
export PYTHONPATH=$PYTHONPATH:`pwd`
Once installed, you have to create a fab app
vi /usr/bin/fab
Then you want to add the following contents to it
#!/usr/bin/env python
from fabric.main import main
main()
Then you want to give it the correct permissions
chmod +x /usr/bin/fab
Now create a directory and place a fabfile.py file in it.
Now create a config.yml file and use the following as a simple template
default:
shell: /bin/bash -l -c
servers:
directory: /dir
hosts:
- host1.domain.com
- host2.domain.com
Then your fab file could look something like
from fabric.api import *
env.config_file = 'config.yml'
env.user = 'mzupan'
@task('servers')
def command():
env().multirun('uname -a')
Normally fabric runs in serial, but Tav’s port adds a multirun() function that runs the commands in parallel. BONUS!
Feel free to play around with it and check out his blog post on it to get more commands.
http://tav.espians.com/fabric-python-with-cleaner-api-and-parallel-deployment-support.html
Senior Linux Admin Interview Question #2
You can see all the questions I have compiled here.
Question
You are already logged into a server and a user runs a fork bomb script. How can you stop the fork bomb without restarting the server or bringing any services offline that are currently running?
You also know the name of the running fork bomb script.
Reason for the this question
This will tell you how well the canidate knows about the signals Linux uses with processes. I would think most people would say the easy thing
killall -9 scriptName
This will not work due the nature of a fork bomb. The reason is the killall does not hold a lock on the process table so each one that is killed a new one takes its place in the process table.
Also you will not be able to run a killall due to the shell forking off another shell to run the killall
This question also tells you if the admin knows about Linux internals. That just running a killall will fork a new process buy running exec killall will run the killall in the current process and not fork out a new one
Answer
So for this I will use a fork bomb script that is written in C. Below is an example
#include
int main(void)
{
for(;;)
fork();
return 0;
}
We can compile it like
gcc -o fork fork.c
So the way to stop it is sending a SIGSTOP signal to each fork bomb process and once they are all stopped you can send a SIGKILL to each process.
So if you run a
killall -STOP fork
You will get a error message like resources not avaliable so you cannot run that. You can run it with exec.
exec killall -STOP fork
exec killall -9 fork
That will stop the fork bomb.