crontab expression to schedule a self triggering DAG in Apache Airflow - cron

I have a DAG which has a triggerdagrunoperator to self trigger the same DAG. The DAG code is shared below.
from datetime import timedelta, datetime
from airflow import DAG
from airflow.operators.bash_operator import BashOperator
from airflow.operators.dagrun_operator import TriggerDagRunOperator
default_args = {
'owner': 'ownername',
'depends_on_past': False,
'start_date': datetime(2021,3,2,10,1),
'email': [***#mail.com],
'email_on_failure': True,
'email_on_retry': False,
'retries': 1,
'retry_delay': timedelta(minutes=5)
}
with DAG('self_trigger_dag', schedule_interval=None, max_active_runs=1, catchup=False, default_args=default_args) as dag:
sleep_task = BashOperator(
task_id='sleep_task',
bash_command='sleep 180',
dag=dag,
)
bash_command =BashOperator(
task_id='run_command',
bash_command="my bash_command",
use_legacy_sql=False,
dag=dag,
)
dag_trigger = TriggerDagRunOperator(
task_id='trigger_self',
trigger_dag_id='self_trigger_dag',
dag=dag)
sleep_task >> bash_command >> dag_trigger
The requirement is that the DAG should be scheduled from 8 AM to 9 PM. I cannot give expression like '* 8-21 * * *' as this is a self triggering DAG. Kindly help me with the correct crontab expression or any other alternative.
Thanks in advance.

I was able to achieve the requirement using a time_check DAG that controls the process of my main DAG. Here I am triggering the main DAG at 12 PM and switching it off at 1 AM using time_check DAG.
The time_check DAG code is shared below:
from datetime import timedelta, datetime,timezone,date
from airflow import DAG
from airflow.operators.python_operator import PythonOperator
from airflow.operators.python_operator import BranchPythonOperator
from airflow.operators.email_operator import EmailOperator
from airflow.operators.dagrun_operator import TriggerDagRunOperator
from airflow.models import Variable
default_args = {
'owner': 'owner',
'depends_on_past': False,
'start_date': datetime(2021,3,2,10,1),
'email': ['xxx#xxx.com'],
'email_on_failure': True,
'email_on_retry': False,
'retries': 1,
'retry_delay': timedelta(minutes=5)
}
airflow_variable = 'stream_dag_status'
def check_current_time(**context):
now_utc = datetime.now(timezone.utc)
start_utc = now_utc.replace(hour=12, minute=0, second=0,microsecond=0)
end_utc = now_utc.replace(hour=1, minute=0, second=0,microsecond=0)+ timedelta(days=1)
if now_utc >= start_utc and now_utc < end_utc:
Variable.set(airflow_variable, 'START')
start_stream = 'start_stream'
return start_stream
else:
update_variable = 'update_variable'
return update_variable
def set_airflow_variable(**context):
Variable.set(airflow_variable, 'STOP')
with DAG('time_check', schedule_interval='0 12,1 * * *', max_active_runs=1, catchup=False,
default_args=default_args) as dag:
check_current_time = BranchPythonOperator(task_id='check_current_time', python_callable=check_current_time,
provide_context=True,
dag=dag)
start_stream = TriggerDagRunOperator(
task_id='start_stream',
trigger_dag_id='STREAMING_TEST',
dag=dag)
update_variable = PythonOperator(task_id='update_variable', python_callable=set_airflow_variable,
provide_context=True,
dag=dag)
stop_stream_email = EmailOperator(task_id='stop_stream_email', to='xxx#xxx.com',
subject='Streaming DAG is OFF now',
html_content="<p>Hi,<br><br>Turning streaming DAG to OFF state<br>", dag=dag)
check_current_time >> start_stream
check_current_time >> update_variable >> stop_stream_email
The self triggering DAG code is shared below:
from datetime import timedelta, datetime
from airflow import DAG
from airflow.operators.bash_operator import BashOperator
from airflow.operators.dagrun_operator import TriggerDagRunOperator
from airflow.operators.dummy_operator import DummyOperator
from airflow.operators.python_operator import BranchPythonOperator
from airflow.operators.email_operator import EmailOperator
from airflow.models import Variable
default_args = {
'owner': 'owner',
'depends_on_past': False,
'start_date': datetime(2021,3,2,10,1),
'email': ['xxx#xxx.com'],
'email_on_failure': True,
'email_on_retry': False,
'retries': 1,
'retry_delay': timedelta(minutes=5)
}
airflow_variable = 'stream_dag_status'
def check_airflow_variable(**context):
status = Variable.get(airflow_variable)
if status == 'START':
sleep_task = 'sleep_task'
return sleep_task
else:
send_email = 'email_notify'
return send_email
with DAG('STREAMING_TEST', schedule_interval=None, max_active_runs=1, catchup=False, default_args=default_args) as dag:
check_airflow_variable = BranchPythonOperator(task_id='check_airflow_variable', python_callable=check_airflow_variable,
provide_context=True,
dag=dag)
sleep_task = BashOperator(
task_id='sleep_task',
bash_command='sleep 60',
dag=dag,
)
start_group = DummyOperator(task_id='start_split', depends_on_past=False)
dag_trigger = TriggerDagRunOperator(
task_id='trigger_self',
trigger_dag_id='STREAMING_TEST',
dag=dag)
email_notify = EmailOperator(task_id='email_notify', to='xxx#xxx#tegna.com',
subject='Variable value is STOP',
html_content="<p>Hi,<br><br>Streaming is stopped<br>", dag=dag)
check_airflow_variable >> sleep_task >> start_group >> dag_trigger
check_airflow_variable >> email_notify

Related

Type Error and got an unexpected keyword argument: When passing dict to Python Zeep's Client.Service call

I have the following XML which I am sending to the target web application using SOAPUI and it works.
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:wsu="http://www.docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd">
<soapenv:Header/>
<soapenv:Body>
<RequestMessage xmlns="http://www.ercot.com/schema/2007-06/nodal/ews/message">
<Header>
<Verb>create</Verb>
<Noun>OutageSet</Noun>
<ReplayDetection>
<Nonce>72465</Nonce>
<Created>2022-12-27T00:40:00-07:00</Created>
</ReplayDetection>
<Revision>004</Revision>
<Source>TAEPTC</Source>
<!--Optional:-->
<UserID>API_OutplanOSITCC</UserID>
</Header>
<Payload>
<OutageSet xmlns="http://www.ercot.com/schema/2007-06/nodal/ews">
<Outage>
<OutageInfo>
<outageType>PL</outageType>
<Requestor>
<name>API_OutplanOSITCC</name>
<userFullName>APIOutplanOSITCC</userFullName>
</Requestor>
<Disclaimer>tempdisclaimer</Disclaimer>
<disclaimerAck>true</disclaimerAck>
</OutageInfo>
<TransmissionOutage>
<operatingCompany>TAEPTC</operatingCompany>
<equipmentName>1589</equipmentName>
<equipmentIdentifier>_{072D6FCA-D121-49E7-AC9D-CDF5D4DB3D70}</equipmentIdentifier>
<transmissionType>DSC</transmissionType>
<fromStation>AIRLINE</fromStation>
<outageState>O</outageState>
<emergencyRestorationTime>1</emergencyRestorationTime>
<natureOfWork>OE</natureOfWork>
</TransmissionOutage>
<Schedule>
<plannedStart>2023-01-16T10:00:00</plannedStart>
<plannedEnd>2023-01-17T10:00:00</plannedEnd>
<earliestStart>2023-01-16T10:00:00</earliestStart>
<latestEnd>2023-01-17T12:00:00</latestEnd>
</Schedule>
</Outage>
</OutageSet>
</Payload>
</RequestMessage>
</soapenv:Body>
</soapenv:Envelope>
I am trying to generate the XML using python's zeep module and for that I have the modifeid xml and converting that to dict using xmltodict module.
Below is the XMLtoDIct code sinppet -
import xmltodict
import pprint
import json
my_xml = """
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:wsu="http://www.docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd">
<soapenv:Header/>
<soapenv:Body>
<RequestMessage xmlns="http://www.ercot.com/schema/2007-06/nodal/ews/message">
<Header>
<Verb>create</Verb>
<Noun>OutageSet</Noun>
<ReplayDetection>
<Nonce>72465</Nonce>
<Created>2022-12-27T00:40:00-07:00</Created>
</ReplayDetection>
<Revision>004</Revision>
<Source>TAEPTC</Source>
<!--Optional:-->
<UserID>API_OutplanOSITCC</UserID>
</Header>
<Payload>
<OutageSet xmlns="http://www.ercot.com/schema/2007-06/nodal/ews">
<Outage>
<OutageInfo>
<outageType>PL</outageType>
<Requestor>
<name>API_OutplanOSITCC</name>
<userFullName>APIOutplanOSITCC</userFullName>
</Requestor>
<Disclaimer>tempdisclaimer</Disclaimer>
<disclaimerAck>true</disclaimerAck>
</OutageInfo>
<TransmissionOutage>
<operatingCompany>TAEPTC</operatingCompany>
<equipmentName>1589</equipmentName>
<equipmentIdentifier>_{072D6FCA-D121-49E7-AC9D-CDF5D4DB3D70}</equipmentIdentifier>
<transmissionType>DSC</transmissionType>
<fromStation>AIRLINE</fromStation>
<outageState>O</outageState>
<emergencyRestorationTime>1</emergencyRestorationTime>
<natureOfWork>OE</natureOfWork>
</TransmissionOutage>
<Schedule>
<plannedStart>2023-01-16T10:00:00</plannedStart>
<plannedEnd>2023-01-17T10:00:00</plannedEnd>
<earliestStart>2023-01-16T10:00:00</earliestStart>
<latestEnd>2023-01-17T12:00:00</latestEnd>
</Schedule>
</Outage>
</OutageSet>
</Payload>
</RequestMessage>
</soapenv:Body>
</soapenv:Envelope>
"""
my_dict = xmltodict.parse(my_xml, process_namespaces= True)
#pp = pprint.PrettyPrinter(indent=2)
print(my_dict)
Below is the dict after conversion -
{'http://schemas.xmlsoap.org/soap/envelope/:Envelope': {'http://schemas.xmlsoap.org/soap/envelope/:Header': None, 'http://schemas.xmlsoap.org/soap/envelope/:Body': {'http://www.ercot.com/schema/2007-06/nodal/ews/message:RequestMessage': {'http://www.ercot.com/schema/2007-06/nodal/ews/message:Header': {'http://www.ercot.com/schema/2007-06/nodal/ews/message:Verb': 'create', 'http://www.ercot.com/schema/2007-06/nodal/ews/message:Noun': 'OutageSet', 'http://www.ercot.com/schema/2007-06/nodal/ews/message:ReplayDetection': {'http://www.ercot.com/schema/2007-06/nodal/ews/message:Nonce': '72465', 'http://www.ercot.com/schema/2007-06/nodal/ews/message:Created': '2022-12-27T00:40:00-07:00'}, 'http://www.ercot.com/schema/2007-06/nodal/ews/message:Revision': '004', 'http://www.ercot.com/schema/2007-06/nodal/ews/message:Source': 'TAEPTC', 'http://www.ercot.com/schema/2007-06/nodal/ews/message:UserID': 'API_OutplanOSITCC'}, 'http://www.ercot.com/schema/2007-06/nodal/ews/message:Payload': {'http://www.ercot.com/schema/2007-06/nodal/ews:OutageSet': {'http://www.ercot.com/schema/2007-06/nodal/ews:Outage': {'http://www.ercot.com/schema/2007-06/nodal/ews:OutageInfo': {'http://www.ercot.com/schema/2007-06/nodal/ews:outageType': 'PL', 'http://www.ercot.com/schema/2007-06/nodal/ews:Requestor': {'http://www.ercot.com/schema/2007-06/nodal/ews:name': 'API_OutplanOSITCC', 'http://www.ercot.com/schema/2007-06/nodal/ews:userFullName': 'APIOutplanOSITCC'}, 'http://www.ercot.com/schema/2007-06/nodal/ews:Disclaimer': 'tempdisclaimer', 'http://www.ercot.com/schema/2007-06/nodal/ews:disclaimerAck': 'true'}, 'http://www.ercot.com/schema/2007-06/nodal/ews:TransmissionOutage': {'http://www.ercot.com/schema/2007-06/nodal/ews:operatingCompany': 'TAEPTC', 'http://www.ercot.com/schema/2007-06/nodal/ews:equipmentName': '1589', 'http://www.ercot.com/schema/2007-06/nodal/ews:equipmentIdentifier': '_{072D6FCA-D121-49E7-AC9D-CDF5D4DB3D70}', 'http://www.ercot.com/schema/2007-06/nodal/ews:transmissionType': 'DSC', 'http://www.ercot.com/schema/2007-06/nodal/ews:fromStation': 'AIRLINE', 'http://www.ercot.com/schema/2007-06/nodal/ews:outageState': 'O', 'http://www.ercot.com/schema/2007-06/nodal/ews:emergencyRestorationTime': '1', 'http://www.ercot.com/schema/2007-06/nodal/ews:natureOfWork': 'OE'}, 'http://www.ercot.com/schema/2007-06/nodal/ews:Schedule': {'http://www.ercot.com/schema/2007-06/nodal/ews:plannedStart': '2023-01-16T10:00:00', 'http://www.ercot.com/schema/2007-06/nodal/ews:plannedEnd': '2023-01-17T10:00:00', 'http://www.ercot.com/schema/2007-06/nodal/ews:earliestStart': '2023-01-16T10:00:00', 'http://www.ercot.com/schema/2007-06/nodal/ews:latestEnd': '2023-01-17T12:00:00'}}}}}}}}
however, when I am passing this dict to the request data like below -
request_data = {'http://www.ercot.com/schema/2007-06/nodal/ews/message:RequestMessage': {'http://www.ercot.com/schema/2007-06/nodal/ews/message:Header': {'http://www.ercot.com/schema/2007-06/nodal/ews/message:Verb': 'create', 'http://www.ercot.com/schema/2007-06/nodal/ews/message:Noun': 'OutageSet', 'http://www.ercot.com/schema/2007-06/nodal/ews/message:ReplayDetection': {'http://www.ercot.com/schema/2007-06/nodal/ews/message:Nonce': '72465', 'http://www.ercot.com/schema/2007-06/nodal/ews/message:Created': '2022-12-27T00:40:00-07:00'}, 'http://www.ercot.com/schema/2007-06/nodal/ews/message:Revision': '004', 'http://www.ercot.com/schema/2007-06/nodal/ews/message:Source': 'TAEPTC', 'http://www.ercot.com/schema/2007-06/nodal/ews/message:UserID': 'API_OutplanOSITCC'}, 'http://www.ercot.com/schema/2007-06/nodal/ews/message:Payload': {'http://www.ercot.com/schema/2007-06/nodal/ews:OutageSet': {'http://www.ercot.com/schema/2007-06/nodal/ews:Outage': {'http://www.ercot.com/schema/2007-06/nodal/ews:OutageInfo': {'http://www.ercot.com/schema/2007-06/nodal/ews:outageType': 'PL', 'http://www.ercot.com/schema/2007-06/nodal/ews:Requestor': {'http://www.ercot.com/schema/2007-06/nodal/ews:name': 'API_OutplanOSITCC', 'http://www.ercot.com/schema/2007-06/nodal/ews:userFullName': 'APIOutplanOSITCC'}, 'http://www.ercot.com/schema/2007-06/nodal/ews:Disclaimer': 'tempdisclaimer', 'http://www.ercot.com/schema/2007-06/nodal/ews:disclaimerAck': 'true'}, 'http://www.ercot.com/schema/2007-06/nodal/ews:TransmissionOutage': {'http://www.ercot.com/schema/2007-06/nodal/ews:operatingCompany': 'TAEPTC', 'http://www.ercot.com/schema/2007-06/nodal/ews:equipmentName': '1589', 'http://www.ercot.com/schema/2007-06/nodal/ews:equipmentIdentifier': '_{072D6FCA-D121-49E7-AC9D-CDF5D4DB3D70}', 'http://www.ercot.com/schema/2007-06/nodal/ews:transmissionType': 'DSC', 'http://www.ercot.com/schema/2007-06/nodal/ews:fromStation': 'AIRLINE', 'http://www.ercot.com/schema/2007-06/nodal/ews:outageState': 'O', 'http://www.ercot.com/schema/2007-06/nodal/ews:emergencyRestorationTime': '1', 'http://www.ercot.com/schema/2007-06/nodal/ews:natureOfWork': 'OE'}, 'http://www.ercot.com/schema/2007-06/nodal/ews:Schedule': {'http://www.ercot.com/schema/2007-06/nodal/ews:plannedStart': '2023-01-16T10:00:00', 'http://www.ercot.com/schema/2007-06/nodal/ews:plannedEnd': '2023-01-17T10:00:00', 'http://www.ercot.com/schema/2007-06/nodal/ews:earliestStart': '2023-01-16T10:00:00', 'http://www.ercot.com/schema/2007-06/nodal/ews:latestEnd': '2023-01-17T12:00:00'}}}}}}
print("Call URL")
print(client.service.MarketTransactions(**request_data))
I am getting the below error -
Creating client.
zeep.transports: Loading remote data from: http://www.w3.org/2001/xml.xsd
Making request.
Call URL
Traceback (most recent call last):
File "C:\Users\SGUPTA\PycharmProjects\ERCOT\ERCOT_Test.py", line 110, in <module>
print(client.service.MarketTransactions(**request_data))
File "C:\Users\SGUPTA\PycharmProjects\ERCOT\venv\lib\site-packages\zeep\proxy.py", line 46, in __call__
return self._proxy._binding.send(
File "C:\Users\SGUPTA\PycharmProjects\ERCOT\venv\lib\site-packages\zeep\wsdl\bindings\soap.py", line 123, in send
envelope, http_headers = self._create(
File "C:\Users\SGUPTA\PycharmProjects\ERCOT\venv\lib\site-packages\zeep\wsdl\bindings\soap.py", line 73, in _create
serialized = operation_obj.create(*args, **kwargs)
File "C:\Users\SGUPTA\PycharmProjects\ERCOT\venv\lib\site-packages\zeep\wsdl\definitions.py", line 222, in create
return self.input.serialize(*args, **kwargs)
File "C:\Users\SGUPTA\PycharmProjects\ERCOT\venv\lib\site-packages\zeep\wsdl\messages\soap.py", line 73, in serialize
body_value = self.body(*args, **kwargs)
File "C:\Users\SGUPTA\PycharmProjects\ERCOT\venv\lib\site-packages\zeep\xsd\elements\element.py", line 58, in __call__
instance = self.type(*args, **kwargs)
File "C:\Users\SGUPTA\PycharmProjects\ERCOT\venv\lib\site-packages\zeep\xsd\types\complex.py", line 63, in __call__
return self._value_class(*args, **kwargs)
File "C:\Users\SGUPTA\PycharmProjects\ERCOT\venv\lib\site-packages\zeep\xsd\valueobjects.py", line 106, in __init__
items = _process_signature(self._xsd_type, args, kwargs)
File "C:\Users\SGUPTA\PycharmProjects\ERCOT\venv\lib\site-packages\zeep\xsd\valueobjects.py", line 241, in _process_signature
raise TypeError(
TypeError: {http://www.ercot.com/schema/2007-06/nodal/ews/message}RequestMessage() got an unexpected keyword argument 'http://www.ercot.com/schema/2007-06/nodal/ews/message:RequestMessage'. Signature: `Header: {http://www.ercot.com/schema/2007-06/nodal/ews/message}HeaderType, Request: {http://www.ercot.com/schema/2007-06/nodal/ews/message}RequestType, Payload: {http://www.ercot.com/schema/2007-06/nodal/ews/message}PayloadType`
Process finished with exit code 1
is this because of the namespaces in both RequestMessage and Outageset nodes?
Here is my complete code -
from zeep.wsse.signature import BinarySignature
from zeep.wsse import utils
from datetime import datetime, timedelta
import contextlib
import os
import requests
from requests_pkcs12 import Pkcs12Adapter
from zeep.transports import Transport
from zeep import Client, Settings
from pathlib import Path
from tempfile import NamedTemporaryFile
from cryptography.hazmat.primitives.serialization import Encoding, PrivateFormat, NoEncryption
from cryptography.hazmat.primitives.serialization.pkcs12 import load_key_and_certificates
import random
import logging.config
# USE THE MOST VERBOSE LOGGING LEVEL
logging.config.dictConfig({
'version': 1,
'formatters': {
'verbose': {
'format': '%(name)s: %(message)s'
}
},
'handlers': {
'console': {
'level': 'DEBUG',
'class': 'logging.StreamHandler',
'formatter': 'verbose',
},
},
'loggers': {
'zeep.transports': {
'level': 'DEBUG',
'propagate': True,
'handlers': ['console'],
},
}
})
class BinarySignatureTimestamp(BinarySignature):
def apply(self, envelope, headers):
security = utils.get_security_header(envelope)
created = datetime.utcnow()
expired = created + timedelta(seconds=1 * 60)
timestamp = utils.WSU('Timestamp')
timestamp.append(utils.WSU('Created', created.replace(microsecond=0).isoformat() + 'Z'))
timestamp.append(utils.WSU('Expires', expired.replace(microsecond=0).isoformat() + 'Z'))
security.append(timestamp)
super().apply(envelope, headers)
return envelope, headers
def verify(self, envelope):
return envelope
#contextlib.contextmanager
def pfx_to_pem(pfx_path, pfx_password):
''' Decrypts the .pfx file to be used with requests. '''
pfx = Path(pfx_path).read_bytes()
private_key, main_cert, add_certs = load_key_and_certificates(pfx, pfx_password.encode('utf-8'), None)
with NamedTemporaryFile(suffix='.pem', delete=False) as t_pem:
with open(t_pem.name, 'wb') as pem_file:
pem_file.write(private_key.private_bytes(Encoding.PEM, PrivateFormat.PKCS8, NoEncryption()))
pem_file.write(main_cert.public_bytes(Encoding.PEM))
for ca in add_certs:
pem_file.write(ca.public_bytes(Encoding.PEM))
yield t_pem.name
def generate_nonce(length=15):
"""Generate pseudorandom number."""
return ''.join([str(random.randint(0, 9)) for i in range(length)])
# CERTIFICATES PATHS
api_p12_key = os.path.join('C:\\Users\\SGUPTA\\ALL\\Projects\\AEPE2\\API Outplan OSI TCC MOTE.p12')
api_certificate = os.path.join('C:\\Users\\SGUPTA\\ALL\\Projects\\AEPE2\\OSITCC.crt')
api_pfx_key = os.path.join('C:\\Users\\SGUPTA\\ALL\\Projects\\AEPE2\\API Outplan OSI TCC MOTE.pfx')
# SETUP
wsdl_file = os.path.join('C:\\Users\\SGUPTA\\ALL\\Projects\\AEPE2\\Nodal.wsdl')
api_base_url = "https://testmisapi.ercot.com"
session = requests.Session()
session.mount(api_base_url,
Pkcs12Adapter(pkcs12_filename=api_p12_key, pkcs12_password='HIDDEN'))
session.verify = None
transport = Transport(session=session)
settings = Settings(forbid_entities=False)
# CREATE CLIENT
print("Creating client.")
with pfx_to_pem(pfx_path=api_pfx_key, pfx_password='AEP') as pem_fle:
client = Client(wsdl=wsdl_file, settings=settings, transport=transport,
wsse=BinarySignatureTimestamp(pem_fle, api_certificate, "AEP"))
print("Making request.")
request_data = {'http://www.ercot.com/schema/2007-06/nodal/ews/message:RequestMessage': {'http://www.ercot.com/schema/2007-06/nodal/ews/message:Header': {'http://www.ercot.com/schema/2007-06/nodal/ews/message:Verb': 'create', 'http://www.ercot.com/schema/2007-06/nodal/ews/message:Noun': 'OutageSet', 'http://www.ercot.com/schema/2007-06/nodal/ews/message:ReplayDetection': {'http://www.ercot.com/schema/2007-06/nodal/ews/message:Nonce': '72465', 'http://www.ercot.com/schema/2007-06/nodal/ews/message:Created': '2022-12-27T00:40:00-07:00'}, 'http://www.ercot.com/schema/2007-06/nodal/ews/message:Revision': '004', 'http://www.ercot.com/schema/2007-06/nodal/ews/message:Source': 'TAEPTC', 'http://www.ercot.com/schema/2007-06/nodal/ews/message:UserID': 'API_OutplanOSITCC'}, 'http://www.ercot.com/schema/2007-06/nodal/ews/message:Payload': {'http://www.ercot.com/schema/2007-06/nodal/ews:OutageSet': {'http://www.ercot.com/schema/2007-06/nodal/ews:Outage': {'http://www.ercot.com/schema/2007-06/nodal/ews:OutageInfo': {'http://www.ercot.com/schema/2007-06/nodal/ews:outageType': 'PL', 'http://www.ercot.com/schema/2007-06/nodal/ews:Requestor': {'http://www.ercot.com/schema/2007-06/nodal/ews:name': 'API_OutplanOSITCC', 'http://www.ercot.com/schema/2007-06/nodal/ews:userFullName': 'APIOutplanOSITCC'}, 'http://www.ercot.com/schema/2007-06/nodal/ews:Disclaimer': 'tempdisclaimer', 'http://www.ercot.com/schema/2007-06/nodal/ews:disclaimerAck': 'true'}, 'http://www.ercot.com/schema/2007-06/nodal/ews:TransmissionOutage': {'http://www.ercot.com/schema/2007-06/nodal/ews:operatingCompany': 'TAEPTC', 'http://www.ercot.com/schema/2007-06/nodal/ews:equipmentName': '1589', 'http://www.ercot.com/schema/2007-06/nodal/ews:equipmentIdentifier': '_{072D6FCA-D121-49E7-AC9D-CDF5D4DB3D70}', 'http://www.ercot.com/schema/2007-06/nodal/ews:transmissionType': 'DSC', 'http://www.ercot.com/schema/2007-06/nodal/ews:fromStation': 'AIRLINE', 'http://www.ercot.com/schema/2007-06/nodal/ews:outageState': 'O', 'http://www.ercot.com/schema/2007-06/nodal/ews:emergencyRestorationTime': '1', 'http://www.ercot.com/schema/2007-06/nodal/ews:natureOfWork': 'OE'}, 'http://www.ercot.com/schema/2007-06/nodal/ews:Schedule': {'http://www.ercot.com/schema/2007-06/nodal/ews:plannedStart': '2023-01-16T10:00:00', 'http://www.ercot.com/schema/2007-06/nodal/ews:plannedEnd': '2023-01-17T10:00:00', 'http://www.ercot.com/schema/2007-06/nodal/ews:earliestStart': '2023-01-16T10:00:00', 'http://www.ercot.com/schema/2007-06/nodal/ews:latestEnd': '2023-01-17T12:00:00'}}}}}}
print("Call URL")
print(client.service.MarketTransactions(**request_data))
The same code is working when I am calling another webservice just by sending the header(does not have a namespace) in the request data like below -
from zeep.wsse.signature import BinarySignature
from zeep.wsse import utils
from datetime import datetime, timedelta
import contextlib
import os
import requests
from requests_pkcs12 import Pkcs12Adapter
from zeep.transports import Transport
from zeep import Client, Settings
from pathlib import Path
from tempfile import NamedTemporaryFile
from cryptography.hazmat.primitives.serialization import Encoding, PrivateFormat, NoEncryption
from cryptography.hazmat.primitives.serialization.pkcs12 import load_key_and_certificates
import random
import logging.config
# USE THE MOST VERBOSE LOGGING LEVEL
logging.config.dictConfig({
'version': 1,
'formatters': {
'verbose': {
'format': '%(name)s: %(message)s'
}
},
'handlers': {
'console': {
'level': 'DEBUG',
'class': 'logging.StreamHandler',
'formatter': 'verbose',
},
},
'loggers': {
'zeep.transports': {
'level': 'DEBUG',
'propagate': True,
'handlers': ['console'],
},
}
})
class BinarySignatureTimestamp(BinarySignature):
def apply(self, envelope, headers):
security = utils.get_security_header(envelope)
created = datetime.utcnow()
expired = created + timedelta(seconds=1 * 60)
timestamp = utils.WSU('Timestamp')
timestamp.append(utils.WSU('Created', created.replace(microsecond=0).isoformat()+'Z'))
timestamp.append(utils.WSU('Expires', expired.replace(microsecond=0).isoformat()+'Z'))
security.append(timestamp)
super().apply(envelope, headers)
return envelope, headers
def verify(self, envelope):
return envelope
#contextlib.contextmanager
def pfx_to_pem(pfx_path, pfx_password):
''' Decrypts the .pfx file to be used with requests. '''
pfx = Path(pfx_path).read_bytes()
private_key, main_cert, add_certs = load_key_and_certificates(pfx, pfx_password.encode('utf-8'), None)
with NamedTemporaryFile(suffix='.pem', delete=False) as t_pem:
with open(t_pem.name, 'wb') as pem_file:
pem_file.write(private_key.private_bytes(Encoding.PEM, PrivateFormat.PKCS8, NoEncryption()))
pem_file.write(main_cert.public_bytes(Encoding.PEM))
for ca in add_certs:
pem_file.write(ca.public_bytes(Encoding.PEM))
yield t_pem.name
def generate_nonce(length=15):
"""Generate pseudorandom number."""
return ''.join([str(random.randint(0, 9)) for i in range(length)])
# CERTIFICATES PATHS
api_p12_key = os.path.join('C:\\Users\\SGUPTA\\ALL\\Projects\\AEPE2\\API Outplan OSI TCC MOTE.p12')
api_certificate = os.path.join('C:\\Users\\SGUPTA\\ALL\\Projects\\AEPE2\\OSITCC.crt')
api_pfx_key = os.path.join('C:\\Users\\SGUPTA\\ALL\\Projects\\AEPE2\\API Outplan OSI TCC MOTE.pfx')
# SETUP
wsdl_file = os.path.join('C:\\Users\\SGUPTA\\ALL\\Projects\\AEPE2\\Nodal.wsdl')
api_base_url = "https://testmisapi.ercot.com"
session = requests.Session()
session.mount(api_base_url,
Pkcs12Adapter(pkcs12_filename=api_p12_key, pkcs12_password='AEP'))
session.verify = None
transport = Transport(session=session)
settings = Settings(forbid_entities=False)
# CREATE CLIENT
print("Creating client.")
with pfx_to_pem(pfx_path=api_pfx_key, pfx_password='hidden') as pem_fle:
client = Client(wsdl=wsdl_file, settings=settings, transport=transport,
wsse=BinarySignatureTimestamp(pem_fle, api_certificate, "AEP"))
print("Making request.")
request_data = {
"Header": {
"Verb": "get",
"Noun": "SystemStatus",
"ReplayDetection": {
"Nonce": generate_nonce(),
"Created": "2022-11-10T15:34:00-06:00"},
"Revision": "1",
"Source": "API Outplan OSI TCC",
"UserID": "API_OutplanOSITCC",
}
}
print("Call URL")
print(client.service.MarketInfo(**request_data))
Could anyone please advise how to fix this and what needs to be changed?
Thanks
Sugata

How to run Apache Airflow DAG as Unix user?

i install apache airflow in Azure kubernetes servece AKS and i want run a DAG as Unix user
i add run_as_user to my dags but it's not working
from airflow import DAG
from airflow.operators.bash import BashOperator
from airflow.utils.dates import days_ago
from airflow.models import Variable
from airflow.operators.python_operator import PythonOperator
args = {
'owner': 'airflow',
}
default_args = {
'run_as_user':'ssaxen3',
}
with DAG(
dag_id='sanity_check',
schedule_interval=None,
start_date=days_ago(1),
tags=['platform'],
default_args=default_args,
) as dag:
sanity_check = BashOperator(
task_id='sanity_check',
bash_command='echo "Hello"'
)
sanity_check
if __name__ == "__main__":
dag.cli()

How to pass the dataframe along list in dash framework?

I'm trying to pass the data frame and selected property of a dropdown to the different calling function in dash. I'm able to pass selected value but i don't get data frame. Here is my code.
"""Visualization graph"""
import os
from flask import Flask
import dash
import dash_bootstrap_components as dbc
import dash_core_components as dcc
import dash_html_components as html
from dash.dependencies import Input, Output
import plotly.express as px
import pandas as pd
DIRECTORY_PATH = 'C:/Users/fortu/Desktop/Zuhair/'
directories = [
d for d in (os.path.join(DIRECTORY_PATH, directories) for directories in
os.listdir(DIRECTORY_PATH))
if os.path.isdir(d)
]
external_stylesheets = [
'https://js.api.here.com/v3/3.1/mapsjs-ui.css'
]
# Normally, Dash creates its own Flask server internally. By creating our own,
# we can create a route for downloading files directly:
server = Flask(__name__)
app = dash.Dash(__name__,
external_stylesheets=[dbc.themes.BOOTSTRAP])
app.layout = html.Div(
[
dbc.Row(dbc.Col(
html.Div("Ground truth visualization",
style={'textAlign': 'center',
'color': 'red', 'fontSize': '40px'}),
md=12)),
dbc.Row(
dbc.Col(
html.Div([
dbc.Row([
dbc.Col(html.Div(dbc.Row(dcc.Dropdown(
id='selected-dir',
options=[{'label': i, 'value': i}
for i in directories],
placeholder="Select the directory"),
style={
'marginLeft': '25px',
'display': 'inline-block',
'width': '90%'
}
)), width=2),
dbc.Col(children=[
html.Div(dbc.Row(dcc.Dropdown(
id='selected-csv-fields',
placeholder="Select the field"),
style={
'display': 'inline-block',
'width': '90%'
}
)),
html.Div(dbc.Row(id='intermediate-value'), style={'display': 'none'})
], width=2),
]),
dbc.Row([
dbc.Col(html.Div([
dbc.Row(
[dbc.Col(html.Div(
dcc.Graph(id='line-graph'),
className='bg-dark badge-dark'))]),
dbc.Row([dbc.Col(html.Div(
dcc.Graph(id='stack-graph'),
className='bg-warning'))],
className="row mt-3")]), width=5)
], className="row mt-3")]))
)
]
)
#app.callback(
[Output("selected-csv-fields", "options"),
Output("intermediate-value", "data")],
[Input("selected-dir", "value")]
)
def get_all_csv(selector):
"""Get all the csv from the folder"""
if selector is not None:
csv_files = list(filter(lambda x: '.csv' in x, os.listdir(selector)))
_DF = pd.concat([pd.read_csv(os.path.join(selector, f))
for f in csv_files])
demo = [{'label': i, 'value': i} for i in _DF]
return demo, _DF
return []
#app.callback(
Output("line-graph", "figure"),
Output("stack-graph", "figure"),
[Input("selected-csv-fields", "value"), Input("intermediate-value", "data")]
)
def update_graph(selector, done):
"""display the graph based on selected value."""
if selector is not None:
fig = px.line(done, x="Time", y=selector)
stack = px.histogram(done, x="Time", y=selector, marginal="box",
hover_data=done)
return fig, stack
return {}, {}
if __name__ == "__main__":
app.run_server(debug=True)
When I remove the Output("intermediate-value", "data")] from get_all_csv() and Input("intermediate-value", "data") from update_graph(a, b) respectively it works fine. but when try to pass this parameters it gives me error
ERROR :
Callback error updating selected-csv-fields.options, intermediate-value.data

Airflow connection created without password and connection type

I am trying to create a Snowflake connection in Airflow programmatically using DAG. However, after running the DAG file in Airflow, the connection is created without password and connection type. Please advise. The python code is as below:
default_args = {
'owner': 'airflow',
'depends_on_past': False,
'start_date': airflow.utils.dates.days_ago(2),
'email': ['me#me.com'],
'email_on_failure': False,
'email_on_retry': False,
'retries': 0,
'retry_delay': timedelta(minutes=5),
}
dag = DAG(
'MakeConnection',
default_args=default_args,
description='Test',
schedule_interval=timedelta(days=1),
)
def BuildConnection():
conn = Connection(
conn_id='SNOWFLAKECONNECTION',
conn_type='Snowflake'
host='abc.snowflakecomputing.com',
login='AIRFLOW',
password='123',
schema='PUBLIC',
port=443,
extra=json.dumps(dict(Account='abc')),
)
session = settings.Session() # get the session
session.add(conn)
session.commit()
run_Rule_SOW = PythonOperator(
task_id='BuildConnection',
python_callable=BuildConnection,
dag=dag,
)
Assuming this is using the Snowflake Python connector, I think you might have the wrong parameter for login. Should be user. Its hard to tell from your post what it is that you are seeing, though. Are you getting an error message that you could share?

Python Zeep WSDL Unexpected Elements Traceback

I can't handle this below.
XMLParseError: Unexpected element 'metadata', expected 'id' error.
I also try strict=False settings but that time zeep returned as none.
from zeep import Client
import zeep
wsdl = 'https://api.n11.com/ws/CategoryService.wsdl'
cl = Client(wsdl=wsdl)
request_data = {"auth":{'appKey' : ***,
'appSecret' : **},'categoryId':int(1003221),"pagingData":{'pageSize':1,'currentPage':0}}
print(cl.service.GetCategoryAttributes(**request_data))
Thanks.
I faced the same problem with the same API. My solution is changing zeep's settings.
You should use xsd_ignore_sequence_order=True.
I hope it's not too late.
settings = Settings(strict=False, xml_huge_tree=True, xsd_ignore_sequence_order=True)
read more:
https://docs.python-zeep.org/en/master/settings.html#module-zeep.settings
Solution:
firstly, to check logs:
import logging.config
logging.config.dictConfig({
'version': 1,
'formatters': {
'verbose': {
'format': '%(name)s: %(message)s'
}
},
'handlers': {
'console': {
'level': 'DEBUG',
'class': 'logging.StreamHandler',
'formatter': 'verbose',
},
},
'loggers': {
'zeep.transports': {
'level': 'DEBUG',
'propagate': True,
'handlers': ['console'],
},
}
})
Second:
from zeep import Client
from zeep.plugins import HistoryPlugin
wsdl = 'https://api.n11.com/ws/CategoryService.wsdl'
from zeep import Client, Settings
settings = Settings(strict=False, xml_huge_tree=True)
history = HistoryPlugin()
from zeep.transports import Transport
transport = Transport(timeout=10)
key={'appKey' : '**',
'appSecret' : '**',
}
cat= {'categoryId':1003221}
dat= {'pageSize':1,'currentPage':1}
client = Client(wsdl=wsdl, transport=transport, plugins=[history], settings=settings)
with client.settings(raw_response=False,strict=False, xml_huge_tree=True):
response = client.service.GetCategoryAttributes(key,1003221,pagingData=dat)
#assert response.status_code == 200
#assert response.content
#node = client.create_message(client.service, 'GetCategoryAttributes',key,1003221,pagingData=dat)
from lxml import etree
try:
for hist in [history.last_sent, history.last_received]:
print(etree.tostring(hist["envelope"], encoding="unicode", pretty_print=True))
except (IndexError, TypeError):
# catch cases where it fails before being put on the wire
pass
lastly, you can parse with bs4 for xml content:
from bs4 import BeautifulSoup
soup = BeautifulSoup(ass, 'lxml')
soup.find('category').find('metadata')

Resources