Before I continue the journey towards Docker, I have to digress a bit here. My “awesome” project has to use 32 bit Oracle instance client, and Docker can only run on 64bit. Installing 32bit Oracle instance client on 64bit Ubuntu turns out to be very very difficult. Of course, once you know something, it seems so simple. That is the curse of knowledge: if you know something, it is hard for you to understand why other people find it hard.
I wrote a python scrip to free my brain of having to
remember various commands. The script does:
- Check if Oracle instant client is already installed, if so, prompt user to choose whether to reinstall
- Install 32bit Oracle instant client on 32bit Ubuntu
- Install 64bit Oracle instant client on 64bit Ubuntu
- Install 32bit Oracle instance client on 64bit Ubuntu
- If ora files directory is provided, copy tnsnames.ora, sqlnet.ora files into /usr/lib/oracle/11.2/{}/network/admin
- Check if Oracle instance client has been successfully installed by checking if ldd sqlplus is successful.
The logics implemented by the script largely come from https://mikesmithers.wordpress.com/2011/04/03/oracle-instant-client-on-ubuntu-with-added-aliens/.
This script won’t download Oracle instant client from Oracle
site, you have to manually download.
·
To download 64bit Oracle instant client, go to http://www.oracle.com/technetwork/topics/linuxx86-64soft-092277.html.
·
To download 32bit Oracle instant client, go to http://www.oracle.com/technetwork/topics/linuxsoft-082809.html.
You typically need to download three files: basic, devel, and sqlplus.
Here is how my directory structure looks like:
To run the script, first you need to copy the script and Oracle
instance files into the destination machine, it is not possible to run the
script in a shared folder.
After you run this successfully, you should see this output:
Note that you need to run source
etc/profile to setup oracle environment variables in the shell. The
script is not able to set the environment variable for the shell that it is run
in.
This is because environment variables exist in a per-process
memory space. When a new process is created with fork()
it inherits its parent's environment variables. The child process can’t set
environment variables for its parent process.
If you want to set environment variables for the current
process, for example, set environment variables inside the python process, here
is a trick you can do:
envcmd = ['bash', '-c', 'source /etc/profile.d/oracleclient.sh && env'] proc = subprocess.Popen(envcmd, stdout = subprocess.PIPE) for line in proc.stdout: (key, _, value) = line.partition("=") os.environ[key.strip()] = value.strip()
Below is the python script install_oracle_client.py:
#!/usr/bin/python
import os import sys import subprocess import glob import re class SystemSetup(object): def __init__(self): self.file_insert_header = ( '\n################################################\n', '# author: Apple #\n', '################################################\n') self.rpm_files = { 'basic': '', 'devel': '', 'sqlplus': '' } self.clientbit64 = False self.clientfolder = '' self.osbit64 = False def install_alien(self): print "**************install alien**************" subprocess.check_call([ "apt-get", "-y", "install", "alien"]) def install_libaio1(self): print "**************install libaio1**************" subprocess.check_call(["apt-get", "-y", "install", "libaio1"]) if self.osbit64 and not self.clientbit64: subprocess.check_call(["apt-get", "-y", "install", "libaio1:i386"]) def find_file(self,fn,directory_containing_rpms): fnstr='{}/oracle*'+fn+'*rpm' self.rpm_files[fn] = glob.glob(fnstr.format(directory_containing_rpms)) if len(self.rpm_files[fn]) != 1: print "zero or more than one "+fn+" files exist: you should have only 1 oracle*"+fn+"*rpm file exists!" print self.rpm_files[fn] exit (1) self.rpm_files[fn] = self.rpm_files[fn] [0] if self.clientbit64 and '64' not in self.rpm_files[fn]: print fn + " is not 64, while another file is 64" exit(1) elif not self.clientbit64 and '64' in self.rpm_files[fn]: self.clientbit64=True def install_file(self, fn,directory_containing_rpms): if self.osbit64 == self.clientbit64: subprocess.check_call(['alien','-iv',self.rpm_files[fn]]) elif self.osbit64 and not self.clientbit64: #install32 client on 64bit ubuntu #http://psgplacement.blogspot.com/2013/09/installing-i386-32-bit-rpm-files-in-amd.html subprocess.check_call(['alien', '--to-tgz', '-v', self.rpm_files[fn]]) tgzfile=glob.glob('*'+fn+'*.tgz'.format(directory_containing_rpms)) if not tgzfile: print "can't find the generated "+fn+" tgz file, something must go wrong!" exit(1) subprocess.check_call(['alien', '--to-deb', '-v', tgzfile[0]]) debfile=glob.glob('*'+fn+'*.deb'.format(directory_containing_rpms)) if not debfile: print "can't find the generated "+fn+" deb file, something must go wrong!" exit(1) subprocess.check_call(['dpkg', '-i', debfile[0]]) def oracle_setup(self, directory_containing_rpms, directory_containing_ora): self.find_file('basic',directory_containing_rpms) self.find_file('devel',directory_containing_rpms) self.find_file('sqlplus',directory_containing_rpms) if self.clientbit64: self.clientfolder="client64" else: self.clientfolder="client" osbit=subprocess.check_output(["/bin/uname", "-m"]) if 'x86_64' in osbit: self.osbit64 = True if self.osbit64 and not self.clientbit64: print "************** install i386 libraries**************" subprocess.check_call([ 'dpkg','--add-architecture', 'i386']) subprocess.check_call(['apt-get','update']) subprocess.check_call([ 'apt-get','install', '-y','libc6:i386', 'libncurses5:i386','libstdc++6:i386']) self.install_alien() self.install_libaio1() print "**************install "+ self.rpm_files['basic'] +"**************" self.install_file('basic',directory_containing_rpms) print "************** install "+ self.rpm_files['devel'] +"**************" self.install_file('devel',directory_containing_rpms) print "************** install "+ self.rpm_files['sqlplus'] +"**************" self.install_file('sqlplus',directory_containing_rpms) print "************** setup /etc/ld.so.conf.d/oracleclient.conf **************" oracle_configuration_file = open('/etc/ld.so.conf.d/oracleclient.conf', 'w') oracle_configuration_file.writelines(self.file_insert_header) oracle_configuration_file.write("/usr/lib/oracle/11.2/{}/lib\n".format(self.clientfolder)) oracle_configuration_file.close() subprocess.check_call(["ldconfig"]) print "************** setup /etc/profile.d/oracleclient.sh **************" system_environment_vars = open('/etc/profile.d/oracleclient.sh', 'w') system_environment_vars.writelines(self.file_insert_header) system_environment_vars.write( 'export ORACLE_HOME=/usr/lib/oracle/11.2/{}\n'.format(self.clientfolder)) system_environment_vars.write( 'export TNS_ADMIN=/usr/lib/oracle/11.2/{}/network/admin\n'.format(self.clientfolder)) system_environment_vars.write( 'export LD_LIBRARY_PATH=/usr/lib/oracle/11.2/{}/lib\n'.format(self.clientfolder)) system_environment_vars.close() subprocess.check_call(["chmod", "+x", "/etc/profile.d/oracleclient.sh"]) #this actually doesn't work, /etc/profile is run inside the bash process, the environment variables are not set on the process that runs the python # subprocess.Popen("source /etc/profile",shell=True, executable="/bin/bash") print "************** create "+"/usr/lib/oracle/11.2/{}/network/admin".format(self.clientfolder)+" **************" if not os.path.exists("/usr/lib/oracle/11.2/{}/network/admin".format(self.clientfolder)): os.makedirs('/usr/lib/oracle/11.2/{}/network/admin'.format(self.clientfolder)) if directory_containing_ora: #check_call will not glob file names, http://stackoverflow.com/questions/14482135/shell-expansion-in-python-subprocess #subprocess.check_call(["cp", directory_containing_ora+"/*", '/usr/lib/oracle/11.2/{}/network/admin'.format(self.clientfolder) ]) cpCmd="cp "+directory_containing_ora + '/*.ora ' + '/usr/lib/oracle/11.2/{}/network/admin'.format(self.clientfolder) subprocess.call(cpCmd, shell=True) else: print "you need to obtain sqlnet.ora, tnsnames.ora, and possibly ldap.ora from your DBA" print "and place these files into " +'/usr/lib/oracle/11.2/{}/network/admin'.format(self.clientfolder) def pre_check(self): sqlplus=subprocess.check_output(["whereis", "sqlplus"]) m=re.search(r'sqlplus:(.*)',sqlplus) if not m or not m.group(1): return True where=m.group(1).strip().split(" ")[0] try: lddret=subprocess.check_output(["ldd", where]) m=re.findall(r'(.*) => not found$',lddret,re.M) if m: for notFound in m: # i18n can be ignored if not "i18n" in notFound: print "sqlplus is installed, but its dependency "+notFound +" is not found, something might be wrong with the installation!" print "would you like to reinstall? press y to reinstall" userput=raw_input() if userput== 'Y' or userput == 'y': return "install" else: print "sqlplus is installed, and it appears to be ok" print "would you like to reinstall? press y to reinstall" userput=raw_input() if userput== 'Y' or userput == 'y': return True except: print where+"exists, but ldd "+where+" failed, will try to reinstall sqlplus" return True return False def post_check(self): sqlplus=subprocess.check_output(["whereis", "sqlplus"]) m=re.search(r'sqlplus:(.*)',sqlplus) if not m or not m.group(1): print "can't find sqlplus, , something might be wrong with the installation!" exit(1) where=m.group(1).strip().split(" ")[0] lddret=subprocess.check_output(["ldd", where]) m=re.findall(r'(.*) => not found$',lddret,re.M) if m: for notFound in m: # i18n can be ignored if not "i18n" in notFound: print notFound +" is not found, something might be wrong with the installation!" exit(1) def clean_up(self): subprocess.call("rm *.deb", shell=True) subprocess.call("rm *.tgz", shell=True) if __name__ == '__main__': setup = SystemSetup() if setup.pre_check(): if len(sys.argv) > 1: setup.oracle_setup(sys.argv[1], sys.argv[2] if len(sys.argv) > 2 else None) else: setup.oracle_setup(".", None) setup.post_check() setup.clean_up() print "Note, you will need to run source /etc/profile to make the environment variables defined in /etc/profile.d/oracleclient.sh to take effect!"
No comments:
Post a Comment