I am trying to load data into GCP using Spark from outside of GCP (from one of our on-prem clusters). To do that, I wrote the following code.
val conf = new SparkConf()
.set("spark.network.timeout", "12000s")
.set("spark.kryoSerializer.buffer.max", "512m")
.set("temporaryGcsBucket", "GCS_BUCKET_LOCATION")
.setAppName(args(1))
conf.registerKryoClasses(Array(classOf[Loader]))
val spark = SparkSession.builder().
appName("app").
master("yarn").
config( "spark.serializer", "org.apache.spark.serializer.KryoSerializer").
config(conf).
getOrCreate()
spark.conf.set("temporaryGcsBucket", "GCS_BUCKET_LOCATION")
spark.conf.set("parentProject", "PROJECTID")
spark.sparkContext.hadoopConfiguration.set("google.cloud.auth.service.account.enable", "true")
spark.sparkContext.hadoopConfiguration.set("fs.gs.impl", "com.google.cloud.hadoop.fs.gcs.GoogleHadoopFileSystem")
spark.sparkContext.hadoopConfiguration.set("google.cloud.auth.service.account.json.keyfile", "/path/to/application_default_credentials.json")
spark.sparkContext.hadoopConfiguration.set("fs.gs.auth.client.id", "CLIENTID")
spark.sparkContext.hadoopConfiguration.set("fs.gs.auth.client.secret", "SECRETKEY")
spark.sparkContext.hadoopConfiguration.set("fs.AbstractFileSystem.gs.impl", "com.google.cloud.hadoop.fs.gcs.GoogleHadoopFS")
spark.sparkContext.hadoopConfiguration.set("fs.gs.project.id", "PROJECTID")
Spark Read:
val dataframe = spark.read.format("jdbc")
.option("url", s"jdbc:sqlserver://$server;DatabaseName=$databasename")
.option("driver", "com.microsoft.sqlserver.jdbc.SQLServerDriver")
.option("user", "USERNAME")
.option("password", "PASSWORD")
.option("dbtable", query)
.option("partitionColumn", partitionColumn)
.option("lowerBound", SOMEVALUE)
.option("upperBound", SOMEVALUE)
.option("numPartitions", numPartitions)
.option("fetchsize", 10000)
.load()
Spark Write:
dataframe.drop(s"${partitionColumn}1")
.write.format("parquet")
.option("parentProject", "PROJECTNAME")
.option("path", s"gs://SOME_GCS_PATH/${tablename}")
.option("credentialsFile","/path/of/jsonfile/on/local/application_default_credentials.json")
.mode("append")
.save()
When I run the code, I see the below error message:
java.lang.IllegalArgumentException: No valid credential configuration discovered: [CredentialOptions{serviceAccountEnabled=false, serviceAccountPrivateKeyId=<redacted>, serviceAccountPrivateKey=<redacted>, serviceAccountEmail=hadoop-distp-sa-hadoop@ktest.imp.gserviceaccount.com, serviceAccountKeyFile=null, serviceAccountJsonKeyFile=/path/of/jsonfile/on/local/application_default_credentials.json, nullCredentialEnabled=false, transportType=JAVA_NET, tokenServerUrl=https://oauth2.googleapis.com/token, proxyAddress=null, proxyUsername=null, proxyPassword=null}]
So I tried to add the configuration as per the method3 present in Authentication section of this page.
and made the following changes to my configuration:
spark.sparkContext.hadoopConfiguration.set("google.cloud.auth.service.account.enable", "false")
spark.sparkContext.hadoopConfiguration.set("fs.gs.auth.impersonation.service.account.for.user.<USER_NAME>", "username@companyname.com")
spark.sparkContext.hadoopConfiguration.set("fs.gs.auth.impersonation.service.account.for.group.<GROUP_NAME>", "gcp_projectid")
spark.sparkContext.hadoopConfiguration.set("fs.gs.auth.impersonation.service.account", "service-account-name@.iam.gserviceaccount.com")
But I am still running into the same exception even after changing the configuration as per the above mentioned link.
Is there any thing that I am doing wrong here ? Could anyone let me know how can I fix the issue and what are the mandatory configuration parameters to provide in spark code to authenticate with GCP ? Any help is really appreciated.