Got NoClassDefFound when running jcraft sshexec from Grails controller - grails

I've got groovy class which is calling AntBuilder.sshexec method to execute remote command. This is working fine when I'm running this Groovy class as Java application. But, when I'm trying to call this class/method from controller, I've got error "Could not create type sshexec due to java.lang.NoClassDefFoundError: com/jcraft/jsch/UserInfo".
Groovy class:
package filemanager
import com.jcraft.jsch.*
import com.jcraft.jsch.ChannelSftp.*
class FileWork {
String servName
String servUser
String servPassword
String servFolder
String localFolder
int servPort
String fileName
FileWork (String p_servName, String p_servUser, String p_servPassword, String p_servFolder, String p_localFolder, int p_servPort,String p_fileName) {
println 'Exec constructor'
this.servName = p_servName
this.servUser = p_servUser
this.servPassword = p_servPassword
this.servFolder = p_servFolder
this.localFolder = p_localFolder
this.servPort = p_servPort
this.fileName = p_fileName
}
.....
String runRemoteCommand () {//(Session p_ses) {
try {
def result = ''
def ant = new AntBuilder()
ant.sshexec(
host: servName,
port: servPort,
trust: true,
username: servUser,
password: servPassword,
command: "unzip -o ${servFolder}${fileName} -d ${servFolder}",
outputproperty: 'result',
verbose: false
)
return result
} catch (Exception e) {
println 'This is filemanager.FileWork.runRemoteCommandException'
e.printStackTrace();
}
}
}
Controller:
package filemanager
import com.jcraft.jsch.*
import com.jcraft.jsch.ChannelSftp.*
class ChooseToController {
def index(params) {
params.max = Math.min(max ?: 10, 100)
//render params
//model:[destServ: DestServ, fileName:fileName]
}
def copyToRemote(params) {
def destServ = DestServ.get(params.id)
//FileWork fileWork = new FileWork (destServ.getDestServName(), destServ.getDestServUser(), destServ.getDestServPassword(), destServ.getDestServFolder(), "C:/tmp/", destServ.getDestServPort(), params.fileName)
//Session ses = fileWork.connect()
//fileWork.copyToRemoteServ(ses)
//ses.disconnect()
FileWork fileWork3 = new FileWork ("###########", "test", "Test123", "/home/test/IN/", "C:/tmp/", 22, "1.zip")
String result = fileWork3.runRemoteCommand()
println(result)
}
}
Dependencies:
runtime "com.jcraft:jsch:0.1.51"
runtime "org.apache.ant:ant-jsch:1.8.1"
Error:
Could not create type sshexec due to java.lang.NoClassDefFoundError: com/jcraft/jsch/UserInfo
at org.apache.tools.ant.AntTypeDefinition.createAndSet(AntTypeDefinition.java:278)
at org.apache.tools.ant.AntTypeDefinition.icreate(AntTypeDefinition.java:219)
at org.apache.tools.ant.AntTypeDefinition.create(AntTypeDefinition.java:206)fro.....
Seems that not all classes are visible from grails runtime context...

Related

Grails 3.3.11 Integration Test (GrailsApplication)

I am now in trouble with the configuration variable GrailsApplication in my Integration Tests. I don't know why, but, I am not managing to get its value when testing my api. I am using Grails 3.3.11. The value of the variable is being null and, due to it, I can't authenticate to perform the tests. I would appreciate your help. I am using Grails 3.3.11.
package br.com.xxx.id.test.integration
//Imports were moved out to simplify understanding
class IdControllerSpec extends Specification {
def grailsApplication
#Value('${local.server.port}')
Integer serverPort
String accessToken
String baseUrl
JSONObject documentPropertiesForTesting
JSONObject documentForTesting
String partTest
String userTest
String typeIdTest
String refreshToken
void setup(){
baseUrl = "http://localhost:${serverPort}/cmbid/api/v1"
partTest = "partTest"
}
void "Saving a new and valid document properties"() {
when:
refreshToken = grailsApplication.config.getProperty('refreshToken')
accessToken = "Bearer " + authenticateXxxAut()
documentPropertiesForTesting = createNewTestDocumentProperties()
typeIdTest = documentPropertiesForTesting.get("message").toString().substring(20,52)
then:
documentPropertiesForTesting.get("status") == "ok"
documentPropertiesForTesting.get("message").contains("properly saved!")
cleanup:
DocumentProperties.withNewSession {
def dp = DocumentProperties.findById(typeIdTest)
dp.delete(flush: true)
}
}
def authenticateXxxAut() {
CloseableHttpClient httpClient = HttpClients.createDefault();
String response = ""
try {
JSONObject responseBody
println('****************************')
println(grailsApplication.config.getProperty('aut.newTokenUrl'))
println(grailsApplication.config.getProperty('refreshToken)'))
println('****************************')
def httpPost = new HttpPost(grailsApplication.config.getProperty('aut.newTokenUrl') + grailsApplication.config.getProperty('refreshToken)'))
CloseableHttpResponse httpResponse = httpClient.execute(httpPost)
if (httpResponse.getStatusLine().getStatusCode() == 200) {
responseBody = new JSONObject(EntityUtils.toString(httpResponse.getEntity()))
response = responseBody.get("access_token")
} else {
response = httpResponse.getStatusLine().getStatusCode().toString()
}
} catch (Exception e){
print(e.getLocalizedMessage())
} finally {
httpClient.close()
return response
}
}
I've been upgrading a Grails 2.x app to version 3.3.11 and just referencing the (provided) variable serverPort worked for me. The IDE shows it as being uninitialized but running the tests, it gets the correct value assigned. I also have my test classes annotated with #Integration(applicationClass = Application.class).
Here's how I get the URL to point against:
def url = "http://localhost:${serverPort}${grailsApplication.config.getProperty('server.contextPath', String, '')}"

"No such library resource" error in JenkinsFile

When I run build I get this error:
ERROR SENDING EMAIL hudson.AbortException: No such library resource build/email.html.groovy could be found.
The file "email.html.groovy" is in the same directory.
An error appears on the line:
def fileContents = libraryResource(fileName)
My Groovy file with 2 functions:
package workflowlibs.manager;
import groovy.text.StreamingTemplateEngine
/**
* This method returns a string with the template filled with groovy variables
*/
def emailTemplate(params) {
def fileName = "build/email.html.groovy"
def fileContents = libraryResource(fileName)
def engine = new StreamingTemplateEngine()
return engine.createTemplate(fileContents).make(params).toString()
}
/**
* This method send an email generated with data from Jenkins
* #param buildStatus String with job result
* #param emailRecipients Array with emails: emailRecipients = []
*/
def notifyEmail(buildStatus, emailRecipients) {
try {
def icon = "✅"
def statusSuccess = true
def hasArtifacts = true
if(buildStatus != "SUCCESSFUL") {
icon = "❌"
statusSuccess = false
hasArtifacts = false
}
def body = emailTemplate([
"jenkinsText" : env.JOB_NAME,
"jenkinsUrl" : env.BUILD_URL,
"statusSuccess" : statusSuccess,
"hasArtifacts" : hasArtifacts,
"downloadUrl" : "www.downloadurl.com"
]);
mail (to: emailRecipients.join(","),
subject: "${icon} [ ${env.JOB_NAME} ] [${env.BUILD_NUMBER}] - ${buildStatus} ",
body: body,
mimeType: 'text/html'
);
} catch (e){
println "ERROR SENDING EMAIL ${e}"
}
}
return this;

Executing CURL in Shared Library Jenkins Pipeline Using `Process`

I have a method in a shared library in my Jenkins pipeline. The idea is to use this library and upload files to a remote host. The library is imported in a singleton library.
import com.package.jobutil.UploadFile
def uploadFunc() {
def uploader = new UploadFile(this)
withCredentials ([usernamePassword(credentialsId: 'user', userNameVariable: 'username', passwordVariable:'password)]) {
uploader.uploadArtifact("${username}", "${password}", file.txt, location)
}
}
def call() {
uploadFunc()
}
The class that is instantiated looks like this:
class UploadFile {
def steps
UploadFile (steps) {
this.steps = steps
}
pulic uploadArtifct (String user, String password, String file, String location) {
Process proc
def cred = "${user}:${pass}"
def cmd = ["curl", "-v", "-u", cred, "--upload-file", file, location]
steps.println "CURL: ${cmd}"
proc = cmd.execute()
}
}
Even though I see the println line in the logs. I do not see the curl command being executed.
Is there something I am missing that does not invoke the cmd.execute to work?
EDIT
When I use the curl directly in the library, it works.
pulic uploadArtifct (String user, String password, String file, String
location) {
def cred = "${user}:${password}"
def cmd = "curl -v -u ${cred} --upload-file ${file} ${nexusLocation}/${file}"
try {
steps.sh cmd
} catch (Exception e) {
throw new RuntimeExceptipon("Cannot execute curl, exception: [${e.getClass().getName()} - '${e.getMessage()}']")
}
}
However, when trying to use the Process it does not work.
pulic uploadArtifct (String user, String password, String file, String
location) {
def cred = "${user}:${password}"
def cmd = ["curl", "-v", "-u", cred, "--upload-file", ${file}, ${location}]
try {
def sout = new StringBuffer(), serr = new StringBuffer()
def proc = cmd.execute()
proc.consumeProcessOutput(sout, serr)
proc.waitForOrKill(1000)
println sout
} catch (Exception e) {
throw new RuntimeExceptipon("Cannot execute curl, exception: [${e.getClass().getName()} - '${e.getMessage()}']")
}
}
The exception I get is:
java.lang.RuntimeException: Cannot execute curl, exception: [groovy.lang.MissingMethodException - 'No signature of method: java.lang.String.div() is applicable for argument types: (org.codehaus.groovy.runtime.GStringImpl) values: [file.txt]
As explained here, you need to capture stdout/stderr to see anything.
At the very least:
def outputStream = new StringBuffer();
proc.waitForProcessOutput(outputStream, System.err)
//proc.waitForProcessOutput(System.out, System.err)
Or, as in this gist:
def sout = new StringBuffer(), serr = new StringBuffer()
def proc = cmd.execute()
proc.consumeProcessOutput(sout, serr)
proc.waitForOrKill(1000)
println sout
An example of blocking call would be:
println new ProcessBuilder( 'sh', '-c', 'du -h --max-depth=1 /var/foo/bar/folder\\ with\\ spaces | sort -hr').redirectErrorStream(true).start().text
def cmd = ["curl", "-v", "-u", cred, "--upload-file", ${file}, ${location}/${file}]
No signature of method: java.lang.String.div() is applicable for argument types: (org.codehaus.groovy.runtime.GStringImpl) values: [file.txt]
The '/' in '${location}/${file}' is interpreted as an '/ (div) operation instead of a string.
Try instead for that curl command argument:
${location}+"/"+${file}
As noted in your subsequent question, the all path needs to be between double-quotes.

Spring Boot Resources in Docker container

I'm using Docker for a Spring Boot application and so far everything is working.
I have a resource file in src/main/resources/db/data/dummydata.csv
In a bootstrap class this file is used to import the dummy data into the database.
private fun getDummyData(): List {
var fileReader: BufferedReader? = null
val dummyData = ArrayList<DummyDataEntity>()
try {
var line: String?
val res = ResourceUtils.getFile("classpath:db/data/dummydata.csv")
fileReader = BufferedReader(FileReader(res.path))
// Read CSV header
fileReader.readLine()
... Processing the data ...
} catch (e: Exception) {
e.printStackTrace()
} finally {
try {
fileReader!!.close()
} catch (e: Exception) {
e.printStackTrace()
}
return dummyData
}
}
When I run the application in IntelliJ, everything works just fine, but when I'm running it in Docker it cannot be found.
The Jar and the Docker image are created using Kotlin DSL Gradle.
import com.palantir.gradle.docker.DockerExtension
import io.spring.gradle.dependencymanagement.dsl.DependencyManagementExtension
import org.gradle.tooling.model.GradleTask
import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
import org.springframework.boot.gradle.tasks.bundling.BootJar
buildscript {
repositories {
mavenCentral()
}
dependencies {
classpath(Libs.springBootGradlePlugin)
classpath(Libs.kotlinGradlePlugin)
classpath(Libs.kotlinAllOpen)
classpath(Libs.gradleDocker)
}
}
plugins {
// Apply the java-library plugin to add support for Java Library
`java-library`
}
apply {
plugin("kotlin")
plugin("kotlin-spring")
plugin("org.springframework.boot")
plugin("io.spring.dependency-management")
plugin("com.palantir.docker")
}
repositories {
mavenCentral()
}
dependencies {
compile(Libs.kotlinReflect)
// Spring Boot
compile(Libs.springBootStarterDataJpa)
}
configure<DependencyManagementExtension> {
imports {
mavenBom(Libs.vaadinBom)
}
}
val bootJar: BootJar by tasks
bootJar.baseName = "reporting-app-site"
bootJar.version = "0.0.1"
configure<DockerExtension> {
name = "brabantia/${bootJar.baseName}"
files(bootJar.archivePath)
buildArgs(mapOf("JAR_FILE" to bootJar.archiveName))
dependsOn(tasks["build"])
}
val compileKotlin: KotlinCompile by tasks
compileKotlin.kotlinOptions.jvmTarget = "1.8"
The Jar does contain BOOT-INF/classes/db/data/dummyData.csv but when the application is run the error that is thrown is
java.io.FileNotFoundException: class path resource [db/data/dummydata.csv] cannot be resolved to absolute file path because it does not reside in the file system: jar:file:/app.jar!/BOOT-INF/classes!/db/data/dummydata.csv
What am I missing here?
The below worked for me.., you need to use an InputStream and not a File.
...
#Autowired
private ResourceLoader resourceLoader;
...
Resource resource= resourceLoader.getResource("classpath:/account_info.html");
InputStream inputStream= resource.getInputStream();
Assert.notNull(inputStream,"Could not load template resource!");
String email = null;
try {
byte[] bdata = FileCopyUtils.copyToByteArray(inputStream);
email = new String(bdata, StandardCharsets.UTF_8);
} catch (IOException e) {
logger.warn("IOException", e);
}finally {
if ( inputStream != null) {
IOUtils.closeQuietly(inputStream);
}
}

Grails with Geb/Spock : Grails doesn't take my baseUrl

I'm using Grails 2.2.1 with the recent Geb version. My Spec test files are under
functional/com.geb.mytest/
My GebConfig is on the same package as my Specs..
import org.openqa.selenium.firefox.FirefoxDriver
import org.openqa.selenium.firefox.FirefoxProfile
driver = {
FirefoxProfile firefoxProfile = new FirefoxProfile()
new FirefoxDriver(firefoxProfile)
}
reportsDir = "target/test-reports"
baseUrl = 'http://myserver.com'
waiting {
timeout = 5
retryInterval = 0.5
presets {
slow {
timeout = 20
retryInterval = 1
}
quick {
timeout = 1.5
retryInterval = 0.3
}
}
}
environments {
}
When I run grails test-app -functional my baseUrl is not taken in consideration...instead I have a localhost url..
Is there a way to avoid putting the baseUrl as an argument in the grails test-app command?
Any idea?
Thanks in advance
Try setting up baseUrl in class which is extended for every test class you have:
class BaseUrlTest extends GroovyTestCase {
def baseURL
#Override
protected void setUp() throws Exception {
super.setUp();
baseURL = 'your url here'
}
}
then your test class looks like this
class myTests extends BaseUrlTest {
void testSomething() {}
}

Resources