I want to connect Python to local Oracle with cx_Oracle. I know that in order to make the connection, I should know the local IP, port and SID. So I get these information through the following steps:
local IP:
import socket
#get local IP:
localhost = socket.gethostbyname(socket.gethostname())
port:
This is from my listener.ora so I use port 1521.
# listener.ora Network Configuration File: C:\app\413022472\product\12.2.0\dbhome_1\network\admin\listener.ora
# Generated by Oracle configuration tools.
SID_LIST_LISTENER =
(SID_LIST =
(SID_DESC =
(SID_NAME = CLRExtProc)
(ORACLE_HOME = C:\app\413022472\product\12.2.0\dbhome_1)
(PROGRAM = extproc)
(ENVS = "EXTPROC_DLLS=ONLY:C:\app\413022472\product\12.2.0\dbhome_1\bin\oraclr12.dll")
)
)
LISTENER =
(DESCRIPTION_LIST =
(DESCRIPTION =
(ADDRESS = (PROTOCOL = TCP)(HOST = DESKTOP-2RE9AJU.local)(PORT = 1521))
(ADDRESS = (PROTOCOL = IPC)(KEY = EXTPROC1521))
)
)
DEFAULT_SERVICE_LISTENER = (orcl)
sid:This bothers me a lot. I tried a lot but still can't get the correct sid. This is from my tnsnames.ora:
# tnsnames.ora Network Configuration File: C:\app\413022472\product\12.2.0\dbhome_1\network\admin\tnsnames.ora
# Generated by Oracle configuration tools.
LISTENER_ORCL =
(ADDRESS = (PROTOCOL = TCP)(HOST = DESKTOP-2RE9AJU.local)(PORT = 1521))
ORACLR_CONNECTION_DATA =
(DESCRIPTION =
(ADDRESS_LIST =
(ADDRESS = (PROTOCOL = IPC)(KEY = EXTPROC1521))
)
(CONNECT_DATA =
(SID = CLRExtProc)
(PRESENTATION = RO)
)
)
ORCL =
(DESCRIPTION =
(ADDRESS = (PROTOCOL = TCP)(HOST = localhost)(PORT = 1521))
(CONNECT_DATA =
(SERVER = DEDICATED)
(SERVICE_NAME = orcl)
)
)
This is what I got when running select instance_name from v$instance; in sqlplus:
INSTANCE_NAME
--------------------------------
orcl
I tried the following:
import cx_Oracle
import socket
#get local IP:
localhost = socket.gethostbyname(socket.gethostname())
#generate dsn:
dsn = cx_Oracle.makedsn(localhost, '1521', service_name = 'orcl')
#make connection:
conn = cx_Oracle.connect("c##scott", "tiger", dsn)
Which gives me:DatabaseError:ORA-12514, TNS:listener does not currently know of service requested in connect descriptor
I also tried dsn = cx_Oracle.makedsn(localhost, '1521', sid = 'orcl')
Which gives me:ORA-12505: TNS:listener does not currently know of SID given in connect descriptorD
I should tell that I changed the text in listener.ora and tnsnames.ora but I can't remember the details. Could anyone help me make the connection success?
In listeners, there are many things that effect in creating a connection.
Below is the content of "listener.ora" file as per my system.
Before that verify your hostname is valid or not by using "hostname" in command prompt. Before replacing the content of listener file takes a copy of your existing listener.ora file. Once you modified the listener.ora file then restarts the listener and Oracle service as well.
LISTENER =
(DESCRIPTION_LIST =
(DESCRIPTION =
(ADDRESS = (PROTOCOL = IPC)(KEY = EXTPROC1))
(ADDRESS = (PROTOCOL = TCP)(HOST = DESKTOP-2RE9AJU.local)(PORT = 1521))
)
)
SID_LIST_LISTENER =
(SID_LIST =
(SID_DESC =
(SID_NAME = CLRExtProc)
(ORACLE_HOME = C:\app\413022472\product\12.2.0\dbhome_1)
(PROGRAM = extproc)
(ENVS = "EXTPROC_DLLS=ONLY:C:\app\413022472\product\12.2.0\dbhome_1\bin\oraclr12.dll")
)
(SID_DESC =
(GLOBAL_DBNAME = orcl.com)
(ORACLE_HOME =C:\app\413022472\product\12.2.0\dbhome_1)
(SID_NAME = orcl)
)
)
DEFAULT_SERVICE_LISTENER = (orcl)
I would use a snippet from this Oracle tutorial (remember to change user/pass accordingly).
import cx_Oracle
con = cx_Oracle.connect('pythonhol/welcome#127.0.0.1/orcl')
print con.version
con.close()
Here's the link to the official cx_Oracle Documentation.
As a last thing, at this GitHub URL you can find several updated examples that could be of help in speeding up your work.
From my experience this can be a really frustrating error to debug. You probably solved the error but l'll add my solution here for anyone who struggles with a similar error connecting to Oracle through cx_Oracle.
Important points to note here:
Although this is a database error, it would not be solved by killing and restarting the database listened service, it is to do with our connection through cx_
Make sure the Oracle client and Python have the same architectures, either both are 32 bit or both are 64 bit. Here's how you can check your Python architecture:
import platform platform.architecture()
Make sure the environment path variable has the complete path of the Oracle client till the bin folder.
Make sure to set the TNS_ADMIN variable to where the TNS file exists.
Connection:
import cx_Oracle conn = cx_Oracle.connect('<username>','<password>','<service name variable in your TNS file>')
This method uses the connection details provided in the TNS file and cx_Oracle accesses the host and port details from the file itself.
Related
I'm trying to connect to a database via python. I keep getting this error when trying to run the code in python:
DatabaseError: ORA-12154: TNS:could not resolve the connect identifier specified
I know the tns settings are good because I can connect to the database via sql developer using the same computer. What's wrong with Python.
host = '205.218.7.153'
port = '1521'
sid= 'pdevl3'
username = 'uname'
password = 'pwd'
connect_str = username + '/' + password + '#' + host + ':' + port + '/' + sid
orcl = cx_Oracle.connect(connect_str)
curs = orcl.cursor()
curs.execute(query2)
rows = curs.fetchall()
curs.close()
Instead of building the string yourself, try using cx_Oracle to help build it for you:
import cx_Oracle
host = '205.218.7.153'
port = '1521'
sid= 'pdevl3'
username = r'uname' # make sure to use an r string if you have any special characters
password = r'pwd'
dsn_tns = cx_Oracle.makedsn(host, port, service_name=sid)
orcl = cx_Oracle.connect(user=username, password=password, dsn=dsn_tns)
Here is the code in the file con = cx_Oracle.connect('/#database_name').
This is setup to use my oracle wallet but its not working for some reason (giving me login denied). How do I enter my user name and password in this line of code? con = cx_Oracle.connect('/#database_name')
You should take a look on
https://cx-oracle.readthedocs.io/en/latest/user_guide/connection_handling.html#establishing-database-connections
To use a wallet with cx_Oracle, you need first to configure the wallet, create the sqlnet.ora and tnsnames.ora files, and you need to use the dsn property
connection = cx_Oracle.connect(dsn="mynetalias", encoding="UTF-8")
Where mynetalias is the TNS entry in your tnsnames.ora
mynetalias =
(DESCRIPTION =
(ADDRESS = (PROTOCOL = TCP)(HOST = yourhost )(PORT = yourport))
(CONNECT_DATA =
(SERVER = DEDICATED)
(SERVICE_NAME = yourservicename)
)
)
Be sure to have the sqlnet.ora configured for using the wallet
WALLET_LOCATION =
(SOURCE =
(METHOD = FILE)
(METHOD_DATA =
(DIRECTORY = /your_wallet_path_directory)
)
)
SQLNET.WALLET_OVERRIDE = TRUE
You can use below,
import cx_Oracle
ip = '192.168.0.1'
port = 1521
service_name = 'my_service'
dsn = cx_Oracle.makedsn(ip, port, service_name=service_name)
db = cx_Oracle.connect('user', 'password', dsn)
import psutil
STATS_URL = ' http://172.20.10.2:8080/report'
SERVER_NAME="test_local_server"
def get_health():
print('generating health report')
cpu_percent = psutil.cpu_percent(interval=2.0)
ctime = psutil.cpu_times()
disk_usage = psutil.disk_usage("/")
net_io_counters = psutil.net_io_counters()
virtual_memory = psutil.virtual_memory()
# The keys in this dict should match the db cols
report = dict (
USER_NAME="USER",
SERVER_NAME="Test_Server",
cpupercent = cpu_percent,
cpu_total = ctime.user + ctime.system,
free_Percnt=((disk_usage.free/disk_usage.used)*100),
bytes_sent = net_io_counters.bytes_sent,
bytes_received = net_io_counters.bytes_recv,
packets_sent = net_io_counters.packets_sent,
packets_received = net_io_counters.packets_recv,
memory_Free = virtual_memory.free,
)
return report
if __name__=='__main__':
print(f'starting health report stream for server :\t{SERVER_NAME}')
while True:
report = get_health()
r = requests.post(STATS_URL, json=report)
time.sleep(20)
I need to send the values of this script which is on an AWS remote server back to my Flask APP which is my main server on my windows laptop.
#app.route("/report",methods=['POST'])
def report():
if request.method=='POST':
time_epoch=time.time()
incoming_report = request.get_json()
print("Generating Health report")
username=incoming_report["USER_NAME"]
server_name=incoming_report["SERVER_NAME"]
disk_free=incoming_report["free_Percnt"]
bytes_sent=incoming_report["bytes_sent"]
bytes_received=incoming_report["bytes_received"]
packets_sent=incoming_report["packets_sent"]
packets_received=incoming_report["packets_received"]
memory_free=incoming_report["memory_Free"]
cpu_percent=incoming_report["cpupercent"]
cpu_total=incoming_report["cpu_total"]
conn=sqlite3.connect("Health.db")
conn.execute(f"create table if not exists {username}_{server_name}
(HEALTH_ID integer primary key AUTOINCREMENT,Time_Epoch integer,Disk_Free varchar(80),Bytes_Sent varchar(80),Bytes_Received varchar(80),Packets_Sent varchar(80),Packets_Received varchar(80),Memory_Free varchar(80),Cpu_Usage_Percent varchar(80),Cpu_Time varchar(80));")
conn.execute(f'insert into {username}_{server_name} (Time_Epoch,Disk_Free,Bytes_Sent,Bytes_Received,Packets_Sent,Packets_Received,Memory_Free,Cpu_Usage_Percent,Cpu_Time) values {time_epoch,disk_free,bytes_sent,bytes_received,packets_sent,packets_received,memory_free,cpu_percent,cpu_total}')
conn.commit()
return {'message': 'success'}
if __name__ ==("__main__"):
app.run(host='0.0.0.0',port=8080)
So i changed the host to '0.0.0.0' cause when i checked online thats what i found to make the flask app public but the connection from script says connection timed out.Can someone please help me send the values from the python script back to my flask app?
You need to forward port 8080 on your router. Right now your home router is also a firewall and doesn't permit anything initiating a connection with a LAN machine (your PC). It needs to be told "if anyone tries to connect to our home IP at port 8080, connect it to my PC at the internal IP x.x.x.x"
I have a file that looks like this
[host1]
connection_type = mysql
database = master
port = 5432
host = aaa_host1
[host2]
connection_type = psql
database = master
port = 5432
host = bbb_host2
[host3]
connection_type = mysql
database = master
port = 5432
host = ccc_host3
[host4]
connection_type = mysql
database = master
port = 5432
client = aaa_host4
This file goes on with a lot of hosts. I'm trying to find each host with a particular client code (ie aaa) and output those stanzas to a file. My current code is below.
myhost = sys.argv[1]
stanzas = []
with open("/dir/to/file/file.txt") as f:
lines = f.read()
for entry in lines.split("\n\n"):
for line in entry:
if line.startswith(clientcode):
host = line.split("=")[-1]
if host.startswith(myhost):
stanzas.append(entry)
This is obviously very wrong and ugly, is there a better way to split by empty line and parse that stanza that I'm unaware of? If I added a print(line) for the for line in entry iteration it prints the letters vertically so not getting the loop right.
You can use Python's built-in configparser, since your file is valid .ini.
import configparser
def find_hosts(clientcode):
hosts = []
config = configparser.ConfigParser()
config.read('file.txt')
for host in config.sections():
for key, value in config.items(host):
if key == 'host' and value.startswith(clientcode):
hosts.append(config.items(host))
return hosts
print(find_hosts("aaa"))
Output:
[[('connection_type', 'mysql'), ('database', 'master'), ('port', '5432'), ('host', 'aaa_host1')]]
I'm trying to connect to a scylladb cluster on compose using the Address Translation Map.
I can only get the code working if I hard code the port when instantiating the Cluster instance:
from cassandra.cluster import Cluster
from cassandra.policies import AddressTranslator
from cassandra.auth import PlainTextAuthProvider
################################################################################
# our variables
address_map = {
"10.0.24.69:9042": "sl-eu-lon-2-portal.3.dblayer.com:15227",
"10.0.24.71:9042": "sl-eu-lon-2-portal.2.dblayer.com:15229",
"10.0.24.70:9042": "sl-eu-lon-2-portal.1.dblayer.com:15228"
}
username = 'scylla'
password = 'changeme'
port = 15227
################################################################################
Next a class for translating the addresses:
class ComposeAddressTranslator(AddressTranslator):
def set_map(self, address_map):
# strip ports from both source and destination as the cassandra python
# client doesn't appear to support ports translation
self.address_map = {key.split(':')[0]: value.split(':')[0] for (key, value) in address_map.items()}
def contact_points(self):
return [value.split(':')[0] for (key, value) in address_map.items()]
def translate(self, addr):
# print some debug output
print('in translate(self, addr) method', type(addr), addr)
trans_addr = self.address_map[addr]
return trans_addr
Now let's connect:
compose_translator = ComposeAddressTranslator()
compose_translator.set_map(address_map)
auth_provider = PlainTextAuthProvider(
username=username,
password=password
)
# if the port parameter value is removed from below, we are unable
# to establish a connection
cluster = Cluster(
contact_points = compose_translator.contact_points(),
address_translator = compose_translator,
auth_provider = auth_provider,
cql_version = '3.2.1',
protocol_version = 2,
port = port
)
session = cluster.connect()
session.execute("USE my_keyspace;")
session.shutdown()
It appears that the cassandra python library does not support port translation with the translate method? You can see below in my debug output that the addr passed into the translate method is a string ip address value without the port:
in translate(self, addr) method <class 'str'> 10.0.24.69
in translate(self, addr) method <class 'str'> 10.0.24.71
My Environment:
$ pip freeze | grep cassandra
cassandra-driver==3.10
$ pip freeze | grep cassandra
cassandra-driver==3.10
Other Cassandra drivers such as the node driver support port translation. The nodejs translator documentation:
MyAddressTranslator.prototype.translate = function (address, port, callback) {
// Your custom translation logic.
};
Above you can see that the translator receives both the ip address and the port.
However, I don't believe the current Cassandra python driver supports port address translation:
translate(addr)
Accepts the node ip address, and returns a translated address to be used connecting to this node.
Here you can see that the translator only receives the ip address.