Record Level Data truncation on Mainframe server while doing SFTP from spark server - scala

Please read this fully.
I am working on sending a csv file via SFTP from spark application developed in scala to the mainframe server. I am using jsch (java secure channel) package version 0.1.53 version to accomplish the SFTP connection from spark server to mainframe server. I am facing issue that on the mainframe server, the csv file gets truncated to 1024 bytes per record line.
After research, I found that on the mainframe, we have options like using "lrecl" and "recfm" to control the length of each record in the file and the format of that record. But I am unable to integrate these options on scala. I found this answer on stackoverflow which was meant for implementation in Java. When I use the same logic on scala, I am getting the below error:
EDC5129I No such file or directory., file: /+recfm=fb,lrecl=3000 at
at com.jcraft.jsch.ChannelSftp.throwStatusError(ChannelSftp.java:2846)
at com.jcraft.jsch.ChannelSftp._stat(ChannelSftp.java:2198)
at com.jcraft.jsch.ChannelSftp._stat(ChannelSftp.java:2215)
at com.jcraft.jsch.ChannelSftp.ls(ChannelSftp.java:1565)
at com.jcraft.jsch.ChannelSftp.ls(ChannelSftp.java:1526)
Scala code block using the jsch library for establishing the SFTP connection and transferring file is as below:
session = jsch.getSession(username, host, port)
session.setConfig("PreferredAuthentication","publickey")
session.setConfig("MaxAuthTries",2)
System.out.println("Created SFTP Session")
val sftpSessionConfig: Properties = new Properties()
sftpSessionConfig.put("StrictHostKeyChecking","no")
session.setConfig(sftpSessionConfig)
session.connect() //Connect to session
System.out.println("Connected to SFTP Session")
val channel = session.openChannel("sftp")
channel.connect()
val sftpChannel = channel.asInstanceOf[ChannelSftp]
sftpChannel.ls("/+recfm=fb,lrecl=3000") //set lrecl and recfm ---> THROWING ERROR HERE
sftpChannel.put(sourceFile, destinationPath,ChannelSftp.APPEND) //Push file from local to mainframe
Is there any way where we can set these options as the configuration in my scala code using the jsch library? I also tried using the spring-ml's spark-sftp package. But this package also has the problem of data truncation on the mainframe server.
Please help as this issue has become very critical blocker to my project.
EDIT: Updated question with scala code block

From this presentation Dovetail SFTP Webinar on slide 21:
ls /+recfm=fb,lrecl=80
it seems to me there is one '/' too many in your code.
From the error message, I think the SFTP server has the current path in the UNIX file system. You do not set the data set high level qualifier (HLQ) for the data set, do you? I can't see it in the code. Again from the above presentation, do a cd before the ls:
cd //your-hlq-of-choice
This will do two things:
Change the current working directory to the MVS data set side.
Set the HLQ to be used.
Sorry I cannot test myself; I do not know scala.

First, what SFTP server is running on z/OS? If it is the one provided with z/OS (not Dovetail) the command you are executing isn't supported and you will receive a message like Can't ls: "/+recfm=fb,lrecl=80" not found. Which would be valid because that is not valid file. Everything to the right of the / would be considered part of the filename.
I converted your code to Java as I'm not familiar with Scala and didn't have time to learn it. Here was my code sample I used.
import com.jcraft.jsch.JSch;
import java.util.Properties;
import java.util.Vector;
class sftptest {
static public void main(String[] args) {
String username = "ibmuser";
String host = "localhost";
int port = 10022; // Note, my z/OS is running in a docker container so I map 10022 to 22
JSch jsch = new JSch();
String sourceFile = "/";
String destinationPath ="/";
String privateKey = "myPrivateKey";
try {
jsch.addIdentity(privateKey); //add private key path and file
com.jcraft.jsch.Session session = jsch.getSession(username, host, port);
session.setConfig("PreferredAuthentication","password");
session.setConfig("MaxAuthTries", "2");
System.out.println("Created SFTP Session");
Properties sftpSessionConfig = new Properties();
sftpSessionConfig.put("StrictHostKeyChecking","no");
session.setConfig(sftpSessionConfig);
session.connect(); //Connect to session
System.out.println("Connected to SFTP Session");
com.jcraft.jsch.ChannelSftp channel = (com.jcraft.jsch.ChannelSftp) session.openChannel("sftp");
channel.connect();
// com.jcraft.jsch.Channel sftpChannel = (ChannelSftp) channel;
// channel.ls("/+recfm=fb,lrecl=3000"); //set lrecl and recfm ---> THROWING ERROR HERE
// channel.ls("/"); //set lrecl and recfm ---> THROWING ERROR HERE
Vector filelist = channel.ls("/");
for(int i=0; i<filelist.size();i++){
System.out.println(filelist.get(i).toString());
}
// channel.put(sourceFile, destinationPath, com.jcraft.jsch.ChannelSftp.APPEND); //Push file from local to mainframe
} catch (Exception e) {
System.out.println("Exception "+e.getMessage());
}
}
}
For my case I did use an ssh key and not a password. The output with your ls method is:
Created SFTP Session
Connected to SFTP Session
Exception No such file
dropping the + and everything to the right you get:
Created SFTP Session
Connected to SFTP Session
drwxr-xr-x 2 OMVSKERN SYS1 8192 May 13 01:18 .
drwxr-xr-x 7 OMVSKERN SYS1 8192 May 13 01:18 ..
-rw-r--r-- 1 OMVSKERN SYS1 0 May 13 01:18 file 1
-rw-r--r-- 1 OMVSKERN SYS1 0 May 13 01:18 file 2
The main issue is that the z/OS appears to not support the syntax you are using which is provided by a specific SFTP implementation by Dovetail.
If you do not have Dovetail I recommend that since you are sending CSV files that are generally variable in length that you send them as a USS file so that the lines will be properly translated and will be of variable length. Transfer them to USS (regular Unix on z/OS) and then copy them to an MVS file that has a RECFM of VB. Assuming the file is already allocated you could do a cp myuploadedFile.csv "//'MY.MVS.FILE'"

Related

syslog-ng - Passing FILENAME from client to server when using wildcard_file

I am using syslog-ng, to remote log the application logs of multiple containers of the same image. I am using the source config as below.
source s_wild { wildcard-file(
base-dir("/var/myapp/logs")
filename-pattern("*")
recursive(no)
flags(no-parse)
follow-freq(1)
); };
When I am using the logging in the local machine (for testing purposes), using the MACRO, ${FILE_NAME}, it works. But the filename is not being passed on, over network when testing with the remote server.
Aug 3 19:39:46 46fc878e92cf syslog-ng[2320]: Error opening file for writing; filename='', error='Is a directory (21)'
There are around 20-25 files and am looking for auto mapping of the filenames in both client and server side. Is it possible. Not sure how the wildcard_file maps to remote server. Logically it may not be possible. Still wondering on a solution.
I am wondering whether I can avoid manual 1-1 mapping by defining multiple source and destination or using log_prefix.
The $FILE_NAME macro works only if syslog-ng receives messages from a file or a wildcard-file source and it does not work over network(). A couple of options you have here to pass file names over network are:
Use the structured-data section of a RFC 5424 syslog message
Use template() with json-parser() to send messages from client-side and parse them on server side
Use ewmm() (Enterprise-wide message model) which supports delivery of structured messages
In the first method, sending the RFC5424-formatted (IETF-syslog) messages allows you to set the FILE_NAME in the SDATA field. Use the syslog() on the source and destination side instead of network() to send the messages using IETF syslog protocol. The source file wildcard can be defined like this. The whole configuration would be something like below:
syslog-ng client side
source s_wild {
wildcard-file(
base-dir("/var/log_syslog")
filename-pattern("*")
recursive(no)
follow-freq(1)
);
};
rewrite r_set_filename{
set(
"$FILE_NAME",
value(".SDATA.file#18372.4.name")
);
};
rewrite r_use_basename {
subst(
"/var/log_syslog/",
"",
value(".SDATA.file#18372.4.name")
type("string")
flags("prefix")
);
};
destination d_container_logs {
syslog(
"192.168.10.48"
transport("tcp")
port(5141)
);
};
log {source(s_wild); rewrite(r_set_filename); rewrite(r_use_basename); destination(d_container_logs);};
The r_set_filename gets the absolute path of file and we chop-off the path bit and retains only the filename using r_use_basename
syslog-ng server side
source s_network {
syslog(
transport("tcp")
port(5141)
keep_hostname(yes)
);
};
destination d_container_logs {
file(
"/var/sys_log/${.SDATA.file#18372.4.name}"
create_dirs(yes)
);
};
log {source(s_network); destination(d_container_logs);};

Download Sharepoint Online file using Python

I am trying to automate some work processes by using Python to download an Excel file from our SharePoint site. Some background is that I'm fairly new to Python and am mostly self-taught. I have read over many examples here using sharepy, office365, requests, etc. and none seem to work. Below is what I have tried (basically copied from another example) with the error below that:
from office365.runtime.auth.authentication_context import AuthenticationContext
from office365.sharepoint.client_context import ClientContext
from office365.sharepoint.file import File
#Inputs
url_shrpt = "https://company.sharepoint.com/sites/teamsite"
username_shrpt = "user#company.com"
password_shrpt = "password"
folder_url_shrpt = "sites/teamsite/library"
#Authentication
ctx_auth = AuthenticationContext(url_shrpt)
if ctx_auth.acquire_token_for_user(username_shrpt, password_shrpt):
ctx = ClientContext(url_shrpt, ctx_auth)
web = ctx.web
ctx.load(web)
ctx.execute_query()
print("Authenticated into sharepoint as: ",web.properties['Title'])
else:
print(ctx_auth.get_last_error())
#Function for extracting the file names from a folder
global print_folder_contents
def print_folder_contents(ctx, folder_url):
try:
folder = ctx.web.get_folder_by_server_relative_url(folder_url)
fold_names = []
sub_folders = folder.files
ctx.load(sub_folders)
ctx.execute_query()
for s_folder in sub_folders:
fold_names.append(s_folder.properties["Name"])
return fold_names
except Exception as e:
print('Problem printing out library contents: ', e)
######################################################
# Call the function by giving your folder URL as input
filelist_shrpt=print_folder_contents(ctx,folder_url_shrpt)
#Print the list of files present in the folder
print(filelist_shrpt)
Here is the error I receive:
Error: HTTPSConnectionPool(host='login.microsoftonline.com', port=443): Max retries exceeded with url: /extSTS.srf (Caused by NewConnectionError(': Failed to establish a new connection: [WinError 10060] A connection attempt failed because the connected party did not properly respond after a period of time, or established connection failed because connected host has failed to respond'))
After collaborating with some more knowledgeable coworkers, I was told it might be a permissions issue; but I'm not sure how to verify that. Any help and/or advice would be appreciated.

How to query flink's queryable state

I am using flink 1.8.0 and I am trying to query my job state.
val descriptor = new ValueStateDescriptor("myState", Types.CASE_CLASS[Foo])
descriptor.setQueryable("my-queryable-State")
I used port 9067 which is the default port according to this, my client:
val client = new QueryableStateClient("127.0.0.1", 9067)
val jobId = JobID.fromHexString("d48a6c980d1a147e0622565700158d9e")
val execConfig = new ExecutionConfig
val descriptor = new ValueStateDescriptor("my-queryable-State", Types.CASE_CLASS[Foo])
val res: Future[ValueState[Foo]] = client.getKvState(jobId, "my-queryable-State","a", BasicTypeInfo.STRING_TYPE_INFO, descriptor)
res.map(_.toString).pipeTo(sender)
but I am getting :
[ERROR] [06/25/2019 20:37:05.499] [bvAkkaHttpServer-akka.actor.default-dispatcher-5] [akka.actor.ActorSystemImpl(bvAkkaHttpServer)] Error during processing of request: 'org.apache.flink.shaded.netty4.io.netty.channel.AbstractChannel$AnnotatedConnectException: Connection refused: /127.0.0.1:9067'. Completing with 500 Internal Server Error response. To change default exception handling behavior, provide a custom ExceptionHandler.
java.util.concurrent.CompletionException: org.apache.flink.shaded.netty4.io.netty.channel.AbstractChannel$AnnotatedConnectException: Connection refused: /127.0.0.1:9067
what am I doing wrong ?
how and where should I define QueryableStateOptions
So If You want to use the QueryableState You need to add the proper Jar to Your flink. The jar is flink-queryable-state-runtime, it can be found in the opt folder in Your flink distribution and You should move it to the lib folder.
As for the second question the QueryableStateOption is just a class that is used to create static ConfigOption definitions. The definitions are then used to read the configurations from flink-conf.yaml file. So currently the only option to configure the QueryableState is to use the flink-conf file in the flink distribution.
EDIT: Also, try reading this]1 it provides more info on how does Queryable State works. You shouldn't really connect directly to the server port but rather You should use the proxy port which by default is 9069.

FTP timing out on Heroku

Using Apache Commons FTPClient in a Scala application works as expected on my local machine, but always times out when running on Heroku. Relevant code:
val ftp = new FTPClient
ftp.connect(hostname)
val success = ftp.login(username, pw)
if (success) {
ftp.changeWorkingDirectory(path)
//a logging statement here WILL print
val engine = ftp.initiateListParsing(ftp.printWorkingDirectory)
//a logging statement here will NOT print
while (engine.hasNext) {
val files = engine.getNext(5)
//do stuff with files
}
}
By adding some loggings I've confirmed the client is successfully connecting, logging in, and changing the directory. But stops when trying to begin retrieving files (either via the above paged access or unpaged with ftp.listFiles) and throws a connection time out exception (after about 15 minutes).
Any reason the above code works fine locally but not on Heroku?
Turns out FTP has two modes, active and passive, and Apache-Commons' FTPClient defaults to active. Heroku's firewall presumably doesn't allow active FTP (which is why this was functioning properly locally but not once deployed) - changing to passive mode by adding ftp.enterLocalPassiveMode() resolved the issue.

Bouncycastle: CertificateFactory.generateCertificate gives "sequence wrong size for a certificate" on one machine but not on another

I’m trying to open a p7b file and read the CA certificates out of it. Below is my code. It works fine in one machine but in another machine the call to certFactory.generateCertificate throws exception
Error Message:java.lang.IllegalArgumentException: sequence wrong size for a certificate
On both machines I have the same p7b file, and the same bouncycastle jars. The machine where is works is a Windows Xp and the one where it doesn’t work is a Windows 2007 server machine. It is a 64 bit machine but I’m using the 32 bit jvm only.
CertificateFactory certFactory = CertificateFactory.getInstance("X.509",
new BouncyCastleProvider());
java.security.cert.Certificate cert = null;
FileInputStream inStream = new FileInputStream("");
ArrayList<java.security.cert.Certificate> certificates = new ArrayList<java.security.cert.Certificate>();
CAService caService = null;
caService.getCertificateAuthority().setCaCerts(new ArrayList<String>());
while ((cert = certFactory.generateCertificate(inStream)) != null)
{
certificates.add(cert);
StringWriter swrtr = new StringWriter();
PEMWriter writer = new PEMWriter(swrtr);
writer.writeObject(cert);
writer.flush();
caService.getCertificateAuthority().getCaCerts().add(swrtr.toString());
}
I even wrote a standalone program and I’m running even explicitly specifying the java.exe to use but I’m facing the same exception on that machine alone.
c:\jdk1.5.0_14\jre\bin\java.exe -classpath .;bcprov-jdk15-143.jar MSCAConfigurator
Exception in thread "main" java.security.cert.CertificateException: java.lang.IllegalArgumentException: sequence wrong size for a certificate
at org.bouncycastle.jce.provider.JDKX509CertificateFactory.engineGenerateCertificate(Unknown Source)
at java.security.cert.CertificateFactory.generateCertificate(CertificateFactory.java:271)
at MSCAConfigurator.main(MSCAConfigurator.java:31)
Caused by: java.lang.IllegalArgumentException: sequence wrong size for a certificate
at org.bouncycastle.asn1.x509.X509CertificateStructure.<init>(Unknown Source)
at org.bouncycastle.asn1.x509.X509CertificateStructure.getInstance(Unknown Source)
at org.bouncycastle.jce.provider.JDKX509CertificateFactory.readPEMCertificate(Unknown Source)
I have the unlimited strength policy jars present.
C:\jdk1.5.0_14\jre\lib\security>dir *.jar
Volume in drive C has no label.
Volume Serial Number is D214-CB94
Directory of C:\jdk1.5.0_14\jre\lib\security
09/13/2004 04:12 PM 2,486 local_policy.jar
09/13/2004 04:12 PM 2,472 US_export_policy.jar
What’s wrong with this machine? Someone please help before I shoot myself.
Cross-posted and apparently resolved the issue here http://www.coderanch.com/t/528193/Security/CertificateFactory-generateCertificate-gives-sequence-wrong
According to the javadocs, CertificateFactory.generateCertificates() support the PKCS#7 format but CertificateFactory.generateCertificate() does not.