Ninja tricks for groovy system scripting for JavaLand 2016
-
Upload
andrey-adamovich -
Category
Technology
-
view
1.912 -
download
3
Transcript of Ninja tricks for groovy system scripting for JavaLand 2016
01
About me02
Andrey AdamovichBio: Developer, coach, speaker, author
Company: Aestas/IT (http://aestasit.com)
Email: [email protected]
Linkedin: http://www.linkedin.com/in/andreyadamovich
Lanyrd: http://lanyrd.com/profile/andreyadamovich
GitHub: https://github.com/aadamovich
SO: http://stackoverflow.com/users/162792/andreyadamovich
Twitter: @codingandrey, @aestasit
••••••••
03
Exposed to operationsMaintenance scripts (backup, cleaning, monitoring)
Scheduled/CRON jobs (transfers, conversions, notifications)
Automation tasks (deployment, packaging, testing)
Web applications (status pages, back doors, dashboards)
••••
04
Why Groovy?05
Native system scriptingBash, Dash, Zsh, Fish, Csh etc.
Bat, Cmd and, eventually, PowerShell (PoSH)••
06
Arrays in BAT?
07
BASH vs. PoSH
08
Scripting languagesPerl
Python
Ruby
Lua
Javascript
...
••••••
09
Multiplatformsupport
10
Does it workon Windows?
11
Operationalsimplicity
12
Maintainablecode
13
Stableecosystem14
Richextensionlibrary
15
Groovy is just a JAR
16
Reuse JVMknowledge17
sdkman.io
18
sdkman.iocurl ‐s http://get.sdkman.io | bash
sdk install groovy 2.4.6
sdk default groovy 2.4.6
sdk list groovy
01.
02.
03.
04.
19
PoSH GVM> posh‐gvm.psm1 cannot be loaded
> because the execution of scripts
> is disabled on this system.
01.
02.
03.
20
Speed up!21
GroovyServ
22
Files,directories,and otheranimals23
Readingf = new File('test.txt')
String textContent = f.text
byte[] binaryContent = file.bytes
01.
02.
03.
24
Writing If << 'hello, this is a test file'
f.text = new URL('http://server/my_data.json').text
file.bytes = [ 65, 66, 67, 68 ] as byte[]
01.
02.
03.
25
Writing IIfile.text = '''What's in a name? That which we call a rose
By any other name would smell as sweet.'''
file << 'What\'s in a name? That which we call a rose\n'
file << 'By any other name would smell as sweet.'
01.
02.
03.04.
05.
26
Writing IIIfile.withWriter { Writer writer ‐>
writer << 'What\'s in a name? That which we call a rose\n'
writer << 'By any other name would smell as sweet.'
}
file.withOutputStream { OutputStream stream ‐>
stream << 'What\'s in a name? That which we call a rose\n'
stream << 'By any other name would smell as sweet.'
}
01.
02.
03.
04.
05.06.
07.
08.
09.
27
Linebylinedef lines = f.readLines()
lines.each { String line ‐>
println line
}
01.
02.
03.
04.
28
eachLine and eachBytef.eachLine { String line ‐>
println line
}
file.eachByte { int b ‐>
...
}
01.
02.
03.
04.
05.
06.
29
Filtering IoutputFile.withPrintWriter { writer ‐>
inputFile.eachLine { line ‐>
if (!line.startsWith('#')) {
writer.println(line)
}
}
}
01.
02.
03.
04.
05.
06.
07.
30
Filtering IIinputFile.filterLine(outputFile.newWriter()) { line ‐>
!line.startsWith('#')
}
01.
02.
03.
31
Filtering IIIoutputFile.withWriter { Writer writer ‐>
inputFile.withReader { Reader reader ‐>
reader.transformLine(writer) { String line ‐>
line.replaceAll('\t', ' ')
}
}
}
01.
02.
03.
04.
05.
06.
07.
32
Filtering IVinputFile.withReader { reader ‐>
reader.transformLine(outputFile.newWriter()) { line ‐>
line.replaceAll('\t', ' ')
}
}
01.
02.
03.
04.
05.
33
Filtering VoutputFile.text = inputFile.text.replaceAll('\t', ' ')01.
34
Walking thepath
35
eachFile and eachDirf.eachFile { File file ‐>
...
}
f.eachDir { File dir ‐>
...
}
01.
02.
03.
04.
05.
06.
36
Recursive walking IcurrentDir.eachFileRecurse { File file ‐>
println file.name
}
currentDir.eachDirRecurse { File dir ‐>
println dir.name
}
01.
02.
03.
04.
05.
06.
37
Recursive walking IIcurrentDir.traverse { File file ‐>
if (file.name.endsWith('.groovy')) {
println file.name
}
}
01.
02.
03.
04.
05.
38
Recursive walking IIIcurrentDir.traverse(nameFilter: ~/.*\.groovy/) { File file ‐>
println file.name
}
01.
02.
03.
39
Recursive walking IVimport static groovy.io.FileType.*
...
currentDir.traverse(
type: FILES,
nameFilter: ~/.*\.groovy/,
excludeNameFilter: ~/^C.*$/) { File file ‐>
println file.name
}
01.
02.
03.
04.
05.
06.
07.
08.
40
Extending File IFile.metaClass.safeDelete = {
if (exists()) {
if (isDirectory()) {
if (!deleteDir()) {
def msg = "Unable to delete a directory: ${name}"
throw new IOException(msg)
}
...
01.
02.
03.
04.
05.
06.
07.
08.
41
Extending File II ...
} else {
if (!delete()) {
def msg = "Unable to delete a file: ${name}"
throw new IOException(msg)
}
}
}
}
01.
02.
03.
04.
05.
06.
07.
08.
09. 42
Extending File IIIFile f = new File('test.txt')
f.safeDelete()
File d = new File('test_dir')
d.safeDelete()
01.
02.
03.
04.
43
Base script44
Base script IBaseScript.groovy :
abstract class BaseScript extends Script {
static {
File.metaClass.safeDelete = {
if (exists()) {
...
}
}
01.
02.
03.
04.
05.
06.
07.
45
Base script IIdelete.groovy :
new File('idonotexist.txt').safeDelete()01.
46
Base script IIIgroovy ‐b BaseScript delete.groovy01.
47
Externalcommands48
External commands Idef exitValue = "ls ‐l".execute().exitValue()
if (!exitValue) {
println "Command failed with exit code: ${exitValue}"
}
01.
02.
03.
04.
49
External commands IIprintln "ls".execute().text()
println "ls".execute().inputStream.eachLine { println it }
"grep abc".execute().waitForOrKill(1000)
01.
02.
03.
50
External commands IIIProcess process = "command".execute()
def out = new StringBuffer()
def err = new StringBuffer()
process.waitForProcessOutput(out, err)
01.
02.
03.
04.
51
External commands IV"less temp.txt".execute().pipeTo("grep error".execute()).text
def proc1 = "less temp.txt".execute()
def proc2 = "grep error".execute()
proc1 | proc2
println proc2.text
01.
02.
03.
04.
05.
52
Arguments53
CliBuilderdef cli = new CliBuilder(usage:'ls')
cli.a('display all files')
cli.l('use a long listing format')
cli.t('sort by modification time')
def options = cli.parse(args)
01.
02.
03.
04.
05.
54
Defensivescripting
55
Do you likeNPEs?
56
Even simple things can cause NPEJava:
System.out.println(user.
getAddress().
getCity())
Groovy:
println user.
address.
city
01.
02.
03.
01.
02.
03. 57
Safe navigation operator (?.)println user?.
address?.
city
01.
02.
03.
58
Elvis operator (?:)println user?.
address?.
city ?: "No idea"
01.
02.
03.
59
Closures forDSLs
60
Imaginary DSLtransaction {
request {
id = '2L'
name = 'PUT'
amount = 25
}
request {
...
}
}
01.
02.
03.
04.
05.
06.
07.
08.
09.
10.61
DSL: transaction() methoddef transaction(Closure cl) {
def processor = new RequestProcessor()
try {
processor.init()
cl.delegate = processor
cl()
sendRequests()
} finally {
processor.cleanup()
}}
01.
02.
03.
04.
05.
06.
07.
08.
09.
10.62
DSL: request() methodclass RequestProcessor {
def requests = []
def request(Closure cl) {
def request = new Request()
requests << request
cl.delegate = request
cl()
}
...
01.
02.
03.
04.
05.
06.
07.
08.
09. 63
DSL: Request structureclass Request {
String id
String name
String amount
}
01.
02.
03.
04.
05.
64
Datamanipulation
65
XMLimport groovy.util.XmlSlurper
def xmlSource = new File('shakespeare.xml')
def bibliography = new XmlSlurper().parse(xmlSource)
println bibliography.author
bibliography.play
.findAll { it.year.toInteger() > 1592 }
.each { println it.title }
01.
02.
03.
04.
05.
06.
07.
66
JSONimport groovy.json.JsonSlurper
def reader = new FileReader('ui.json')
def ui = new JsonSlurper().parse(reader)
ui.items.each { println it.type }
println ui.items[0]
.axes
.find {
it.fields.contains('y')
}.title
01.
02.
03.
04.
05.
06.
07.
08.
09. 67
Grab yourstuff!
68
@Grab: import@Grab('org.apache.httpcomponents:httpclient:4.2.1')
import org.apache.http.impl.client.DefaultHttpClient
import org.apache.http.client.methods.HttpGet
01.
02.
03.
69
@Grab: variable@Grab('org.apache.httpcomponents:httpclient:4.2.1')
def httpClient =
new org.apache.http.impl.client.DefaultHttpClient()
01.
02.
03.
70
@Grab: method@Grab('org.apache.httpcomponents:httpclient:4.2.1')
def getHttpClient() {
new org.apache.http.impl.client.DefaultHttpClient()
}
01.
02.
03.
04.
71
@Grab: class@Grab('org.apache.httpcomponents:httpclient:4.2.1')
class Searcher {
def httpClient
Searcher() {
httpClient =
new org.apache.http.impl.client.DefaultHttpClient()
}
}
01.
02.
03.
04.
05.
06.
07.
08.
72
@Grab: multiple@Grapes([
@Grab('org.apache.httpcomponents:httpclient:4.2.1'),
@Grab('org.ccil.cowan.tagsoup:tagsoup:1.2')])
class Searcher { ... }
01.
02.
03.
04.
73
@Grab: repository@GrabResolver(name='codehaus',
root='http://repository.codehaus.org/')
class Searcher { ... }
01.
02.
03.
74
@Grab: exclude@GrabExclude(group='commons‐codec',
module='commons‐codec')
class Searcher { ... }
01.
02.
03.
75
HTTP76
HTTPBuilder: import@Grab(
group='org.codehaus.groovy.modules.http‐builder',
module='http‐builder',
version='0.6'
)
import groovyx.net.http.*
01.
02.
03.
04.
05.
06.
77
HTTPBuilder: instantiationdef baseUrl = 'http://api.duckduckgo.com'
def queryString = 'q=groovy&format=json&pretty=1'
def http = new HTTPBuilder(baseUrl)
01.
02.
03.
78
HTTPBuilder: requesthttp.request(Method.POST) {
send ContentType.URLENC, queryString
response.success = { response, reader ‐>
println response.statusLine
println reader.text
}
response.failure = { response ‐>
println response.statusLine
}
}
01.
02.
03.
04.
05.
06.
07.
08.
09.
10.79
SQL80
SQL: settingsimport groovy.sql.Sql
def dbSettings = [
url: 'jdbc:hsqldb:hsql://localhost/cookingdb',
driver: 'org.hsqldb.jdbcDriver',
user: 'sa',
password: ''
]
01.
02.03.
04.
05.
06.
07.
08.
81
SQL: querydef sql = Sql.newInstance(dbSettings)
sql.eachRow('SELECT * FROM COOKBOOK') { cookbook ‐>
printf '%‐20s%s\n',
cookbook.id,
cookbook[1]
}
01.
02.03.
04.
05.
06.
07.
82
Groovy as a server (GaaS?)> groovy ‐l 4444 ‐e "println new Date()" &
> telnet localhost 4444
hey groovy give me the date
Wed Feb 04 10:03:23 EET 2015
01.
02.
03.
04.
83
Ratpack84
Ratpack: import@Grab("io.ratpack:ratpack‐groovy:1.1.1")
import static ratpack.groovy.Groovy.ratpack
01.
02.
85
Ratback: script bodyratpack {
handlers {
get {
response.send "This is the app root (try: /date)"
}
get("date") {
response.send new Date().toString()
}
}
}
01.
02.
03.
04.
05.
06.
07.
08.
09.
10.86
Sshoogr87
Sshoogr: import@Grab(
group='com.aestasit.infrastructure.sshoogr',
module='sshoogr',
version='0.9.16')
import static com.aestasit.ssh.DefaultSsh.*
01.
02.
03.
04.
05.
88
Sshoogr: defaultsdefaultUser = 'root'
defaultKeyFile = new File('secret.pem')
execOptions {
verbose = true
showCommand = true
}
01.
02.
03.
04.
05.
06.
89
Sshoogr: connectionremoteSession {
url = 'user2:654321@localhost:2222'
exec 'rm ‐rf /tmp/*'
exec 'touch /var/lock/my.pid'
remoteFile('/var/my.conf').text = "enabled=true"
}
01.
02.
03.
04.
05.
06.
90
Sshoogr: multiline contentremoteFile('/etc/yum.repos.d/puppet.repo').text = '''
[puppet]
name=Puppet Labs Packages
baseurl=http://yum.puppetlabs.com/el/
enabled=0
gpgcheck=0
'''
01.
02.
03.
04.
05.
06.
07.
91
Sshoogr: file copyingremoteSession {
scp {
from { localDir "$buildDir/application" }
into { remoteDir '/var/bea/domain/application' }
}
}
01.
02.
03.
04.
05.
06.
92
Sshoogr: command resultdef result = exec(command: '/usr/bin/mycmd',
failOnError: false, showOutput: false)
if (result.exitStatus == 1) {
result.output.eachLine { line ‐>
if (line.contains('WARNING')) {
throw new RuntimeException("First warning: ${line}")
}
}
}
01.
02.
03.
04.
05.
06.
07.
08.
09. 93
Sshoogr: shortcutsif (ok('/usr/bin/mycmd')) {
...
}
if (fail('/usr/bin/othercmd')) {
...
}
01.
02.
03.
04.
05.
06.
94
Sshoogr: tunnelstunnel('1.2.3.4', 8080) { int localPort ‐>
def url = "http://localhost:${localPort}/flushCache"
def result = new URL(url).text
if (result == 'OK') {
println "Cache is flushed!"
} else {
throw new RuntimeException(result)
}
}
01.
02.
03.
04.
05.
06.
07.
08.
09. 95
Sshoogr: prefix/suffixprefix('sudo ') {
exec 'rm ‐rf /var/log/abc.log'
exec 'service abc restart'
}
suffix(' >> output.log') {
exec 'yum ‐y install nginx'
exec 'yum ‐y install mc'
exec 'yum ‐y install links'
}
01.
02.
03.
04.
05.
06.
07.
08.
09. 96
Summary97
TakeawaysGroovy scripts are portable.
Groovy scripts are concise.
Groovy scripts are powerful.
Well, the name is groovy as well!
••••
98
Danke schön!99
Questions?100
Happyscripting!
101