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