4

I'm scripting a way to set hostname on a Debian system with Python. I succeed at:

  • getting the new hostname from arg1 or if I define it as the value of a variable
  • get the current hostname
  • open /etc/hostname and write the new hostname from the variable to the file and subsequently close it.
  • open /etc/hosts for reading or writing

I get stuck there. I've tried reading it as a string to do str.replace(oldname, newname), but run into trouble unless I turn the file contents into str. If I do that, I can't write the file.

Alternatively, I've tried re.sub(), but likewise have trouble writing the results to /etc/hosts.

Any feedback is appreciated.

I did research examples and found a solution for CentOS. I've learned from it, but don't see a solution to my problem.

Bash is absolutely the right tool for this job. 3 lines if I don't concatenate. I need a python solution, however.

The code cited above writes to hostname: I've that taken care of that. I'm not finding that the same strategy works with hosts.

Here's working code, thanks for suggestions. They need to be taken into account. I've also left off the conclusion. But this does the narrowly defined job:

#!/usr/bin/python -ex
import os, sys, syslog

#Customize
hosts_file = '/etc/hosts'
hostname_file = '/etc/hostname'

#Check for root
if not os.geteuid()==0:
    sys.exit("\nOnly root can run this script\n")

if len(sys.argv) != 2:
    print "Usage: "+sys.argv[0]+" new_hostname"
    sys.exit(1)

new_hostname = sys.argv[1]

print 'New Hostname: ' +new_hostname

#get old hostname
f_hostname = open('/etc/hostname', 'r')
old_hostname = f_hostname.readline()
old_hostname = old_hostname.replace('/n','')
f_hostname.close()

print 'Old Hostname: ' +old_hostname

#open hosts configuration
f_hosts_file = open(hosts_file, 'r')
set_host = f_hosts_file.read()
f_hosts_file.close()
pointer_hostname = set_host.find(old_hostname)

#replace hostname in hosts_file
set_host = set_host.replace(old_hostname, new_hostname)
set_host_file = open(hosts_file,'w')
set_host_file.seek(pointer_hostname)
set_host_file.write(set_host)
set_host_file.close()

#insert code to handle /etc/hostname

#change this system hostname
os.system('/bin/hostname '+new_hostname)

#write syslog
syslog.syslog('CP : Change Server Hostname')

I then will hope to write a single function to write/replace the new hostname where the old hostname was.

user82345
  • 49
  • 1
  • 3
  • 1
    These interactions with operational system configuration files in Linux are a good use case for `bash` (shell) scripts using `sed`, in case you want to try. What error are you getting, or what is not happening that should be? – heltonbiker Nov 13 '12 at 18:11
  • 2
    Why not use the hostname executable? – uselpa Nov 13 '12 at 18:17
  • You might have to read all the file content and replace the bit you want. Shouldn't be that hard. – andrefsp Nov 13 '12 at 18:18

2 Answers2

1

The link you provided opens the host file for reading, saves its contents in a string, calls replace on the string, closes the file, opens the file for writing and writes the string - how exactly is this not a solution to your problem?

f = open("/etc/hosts", "r")     #open file for reading
contents = f.read()             #read contents
f.close()                       #close file
contents.replace(old, new)      #replace
f = open("/etc/hosts", "w")     #open file for writing
f.write(contents)               #write the altered contents
f.close()                       #close file

You can also do this without closing and re-opening the file by using the r+ mode:

f = open("/etc/hosts", "r+")    #open file with mode r+ for reading and writing
contents = f.read()             #read the file
contents.replace(old, new)      #replace
f.seek(0)                       #reset the file pointer to the start of the file
f.truncate()                    #delete everything after the file pointer
f.write(contents)               #write the contents back
f.close()                       #close the file

Note that using replace is unsafe if you don't take special precautions - e.g. the hostname might be a substring of other hostnames or aliases contained in the hosts file, so the least you should do is surrounding it with spaces before the replace. You also need to make sure that whatever is entered is even valid as a hostname. The easiest way to deal with all of this would probably be calling the OS' built-in hostname command via subprocess.Popen.

l4mpi
  • 5,103
  • 3
  • 34
  • 54
  • seek(0) is dicovered is my problem. It works well for /etc/hostname, but not for /etc/hosts, from what I can tell. – user82345 Nov 13 '12 at 23:39
  • `replace()` doesn't modify the string in-place. You have to reassign it to the variable: `contents = contents.replace(old,new)` – kbuilds Aug 29 '16 at 15:23
1

A Python Function to change the hostname with domain you need an help file named hosts_tail anywhere in your filesytem which looks:

help file hosts_tail

# The following lines are desirable for IPv6 capable hosts
::1     ip6-localhost ip6-loopback
fe00::0 ip6-localnet
ff00::0 ip6-mcastprefix
ff02::1 ip6-allnodes
ff02::2 ip6-allrouters

the Python function:

def set_hostname(hostname,domain):
"""
usage: set_hostname('debian','labor.local')
"""
try:
    os.system('echo 127.0.0.1    localhost > /etc/hosts')
    os.system('echo 127.0.1.1    '+ hostname + '.' + domain + ' ' + hostname +  ' >> /etc/hosts')
    os.system('cat ' + mypath + 'config/hosts_tail >> /etc/hosts')
    os.system('echo ' + hostname + ' > /etc/hostname')
    os.system('echo ' + hostname + '.' + domain + ' > /etc/mailname')
    os.system('cat /etc/resolv.conf | grep nameserver | uniq > /tmp/resolv.tmp')
    os.system("echo domain " + domain + ' > /etc/resolv.conf')
    os.system("echo search " + domain + ' >> /etc/resolv.conf')
    os.system('cat /tmp/resolv.tmp | uniq >> /etc/resolv.conf')
    os.system('rm -rf /tmp/resolv.tmp')
    os.system('/etc/init.d/hostname.sh start')
except Exception, e:
    return False
return True

my debian os :

cat /etc/debian_version
6.0.6
BenMorel
  • 34,448
  • 50
  • 182
  • 322
mtt2p
  • 1,818
  • 1
  • 15
  • 22
  • Your first `os.system` call overwrites the hosts file. All entries would need to be duplicated in your hosts_tail file or get removed by calling your function. Also, catching all exceptions seems bad: If the function is partially executed it could leave the system in an inconsistent state - I would want more information than just a `False` in this case :) For example, your code doesn't define `mypath` anywhere; run just like this it would always return `False` because of an `UnboundLocalError`. – l4mpi Nov 13 '12 at 19:25