Cleanup plugin and add identifying classes to config

Still missing jetty since that requires method level searching.
This commit is contained in:
Tyler Benson 2017-08-18 09:46:57 -06:00
parent d33b468096
commit 988a3d0fdf
14 changed files with 147 additions and 100 deletions

View File

@ -8,10 +8,10 @@ dependencies {
compile gradleApi()
compile localGroovy()
compile group: 'org.eclipse.aether', name: 'aether-impl', version: '1.1.0'
compile group: 'org.eclipse.aether', name: 'aether-connector-basic', version: '1.1.0'
compile group: 'org.eclipse.aether', name: 'aether-transport-http', version: '1.1.0'
compile group: 'org.eclipse.aether', name: 'aether-transport-file', version: '1.1.0'
compile group: 'org.apache.maven', name: 'maven-aether-provider', version: '3.3.9'
compile group: 'com.google.guava', name: 'guava', version: '23.0'
compile group: 'org.ow2.asm', name: 'asm-all', version: '5.2'
}

View File

@ -1,17 +0,0 @@
import org.objectweb.asm.ClassReader
import org.objectweb.asm.tree.ClassNode
import java.util.jar.JarEntry
import java.util.jar.JarFile
class ClassAnalyzer {
static def findMethodNames(JarFile jar, JarEntry entry) {
def stream = jar.getInputStream(entry)
def classNode = new ClassNode()
def cr = new ClassReader(stream)
cr.accept(classNode, 0)
return classNode.methods.collect { it.name }
}
}

View File

@ -2,4 +2,8 @@ class VersionScanExtension {
String group
String module
String versions
boolean scanMethods = false
boolean scanDependencies = false
String legacyGroup
String legacyModule
}

View File

@ -13,13 +13,15 @@ import org.eclipse.aether.resolution.VersionRangeRequest
import org.eclipse.aether.resolution.VersionRangeResult
import org.eclipse.aether.spi.connector.RepositoryConnectorFactory
import org.eclipse.aether.spi.connector.transport.TransporterFactory
import org.eclipse.aether.transport.file.FileTransporterFactory
import org.eclipse.aether.transport.http.HttpTransporterFactory
import org.eclipse.aether.version.Version
import org.gradle.api.Plugin
import org.gradle.api.Project
import org.objectweb.asm.ClassReader
import org.objectweb.asm.tree.ClassNode
import java.util.concurrent.atomic.AtomicReference
import java.util.jar.JarEntry
import java.util.jar.JarFile
/**
@ -36,7 +38,7 @@ class VersionScanPlugin implements Plugin<Project> {
description = "Queries for all versions of configured modules and finds key classes"
}
if (!project.gradle.startParameter.taskNames.contains('scanVersions')) {
if (!project.gradle.startParameter.taskNames.each { it.endsWith('scanVersions') }.any()) {
return
}
@ -78,6 +80,10 @@ class VersionScanPlugin implements Plugin<Project> {
Artifact artifact = new DefaultArtifact(group, module, "jar", versions)
Artifact allVersions = new DefaultArtifact(group, module, "jar", "(,)")
String legacyGroup = project.versionScan.legacyGroup == null ? group : project.versionScan.legacyGroup
String legacyModule = project.versionScan.legacyModule == null ? module : project.versionScan.legacyModule
Artifact allLegacyVersions = new DefaultArtifact(legacyGroup, legacyModule, "jar", "(,)")
VersionRangeRequest rangeRequest = new VersionRangeRequest()
rangeRequest.setRepositories(newRepositories(system, session))
@ -86,100 +92,105 @@ class VersionScanPlugin implements Plugin<Project> {
rangeRequest.setArtifact(allVersions)
VersionRangeResult allResult = system.resolveVersionRange(session, rangeRequest)
def includeVersionSet = Sets.newHashSet(filter(rangeResult.versions))
def excludeVersionSet = Sets.newHashSet(filter(allResult.versions))
def includeVersionSet = Sets.newHashSet(filter(rangeResult.versions).collect {
new DefaultArtifact(group, module, "jar", it.toString())
})
def excludeVersionSet = Sets.newHashSet(filter(allResult.versions).collect {
new DefaultArtifact(group, module, "jar", it.toString())
})
excludeVersionSet.removeAll(includeVersionSet)
if (allVersions != allLegacyVersions) {
// println "Adding legacy versions $allLegacyVersions"
rangeRequest.setArtifact(allLegacyVersions)
VersionRangeResult allLegacyResult = system.resolveVersionRange(session, rangeRequest)
def legacyVersions = filter(allLegacyResult.versions)
// println "Found ${legacyVersions.size()} legacy versions for $legacyGroup:$legacyModule"
excludeVersionSet.addAll(legacyVersions.collect {
new DefaultArtifact(legacyGroup, legacyModule, "jar", it.toString())
})
}
if (excludeVersionSet.empty) {
println "Found ${includeVersionSet.size()} versions, but none to exclude. Skipping..."
scanVersionsReport.enabled = false
return
}
println "Scanning ${includeVersionSet.size()} included and ${excludeVersionSet.size()} excluded versions. Included: $includeVersionSet"
// println "Scanning ${includeVersionSet.size()} included and ${excludeVersionSet.size()} excluded versions. Included: ${includeVersionSet.collect { it.version }}}"
includeVersionSet.each { version ->
def name = "scanVersionInclude-$group-$module-$version"
def config = project.configurations.create(name)
config.dependencies.add(project.dependencies.create("$group:$module:$version"))
def task = project.task(name) {
doLast {
Set<String> contentSet = Sets.newConcurrentHashSet()
project.configurations.getByName(name).resolvedConfiguration.files.each { jarFile ->
def jar = new JarFile(jarFile)
for (jarEntry in jar.entries()) {
if (jarEntry.name.endsWith(".class")) {
if (project.versionScan.scanMethods) {
ClassAnalyzer.findMethodNames(jar, jarEntry).each {
contentSet.add("$jarEntry.name|$it")
}
} else {
contentSet.add("$jarEntry.name")
}
}
}
}
allInclude.addAll(contentSet)
if (!keyPresent.compareAndSet(Collections.emptySet(), contentSet)) {
def intersection = Sets.intersection(keyPresent.get(), contentSet)
keyPresent.get().retainAll(intersection)
}
}
}
project.tasks.scanVersions.finalizedBy(task)
project.tasks.scanVersionsReport.mustRunAfter(task)
addScanTask("Include", new DefaultArtifact(version.groupId, version.artifactId, "jar", version.version), keyPresent, allInclude, project)
}
excludeVersionSet.each { version ->
def name = "scanVersionExclude-$group-$module-$version"
def config = project.configurations.create(name)
config.dependencies.add(project.dependencies.create("$group:$module:$version"))
addScanTask("Exclude", new DefaultArtifact(version.groupId, version.artifactId, "jar", version.version), keyMissing, allExclude, project)
}
}
}
def task = project.task(name) {
doLast {
Set<String> contentSet = Sets.newConcurrentHashSet()
project.configurations.getByName(name).resolvedConfiguration.files.each { jarFile ->
def jar = new JarFile(jarFile)
for (jarEntry in jar.entries()) {
if (jarEntry.name.endsWith(".class")) {
if (project.versionScan.scanMethods) {
ClassAnalyzer.findMethodNames(jar, jarEntry).each {
contentSet.add("$jarEntry.name|$it")
}
} else {
contentSet.add("$jarEntry.name")
}
def addScanTask(String label, Artifact artifact, AtomicReference<Set<String>> keyIdentifiers, Set<String> allIdentifiers, Project project) {
def name = "scanVersion$label-$artifact.groupId-$artifact.artifactId-$artifact.version"
def config = project.configurations.create(name)
config.dependencies.add(project.dependencies.create("$artifact.groupId:$artifact.artifactId:$artifact.version") {
transitive = project.versionScan.scanDependencies
})
def task = project.task(name) {
doLast {
Set<String> contentSet = Sets.newConcurrentHashSet()
project.configurations.getByName(name).resolvedConfiguration.files.each { jarFile ->
def jar = new JarFile(jarFile)
for (jarEntry in jar.entries()) {
if (jarEntry.name.endsWith(".class")) {
if (project.versionScan.scanMethods) {
findMethodNames(jar, jarEntry).each {
contentSet.add("$jarEntry.name|$it")
}
} else {
contentSet.add("$jarEntry.name")
}
}
allExclude.addAll(contentSet)
if (!keyMissing.compareAndSet(Collections.emptySet(), contentSet)) {
def intersection = Sets.intersection(keyMissing.get(), contentSet)
keyMissing.get().retainAll(intersection)
}
}
}
project.tasks.scanVersions.finalizedBy(task)
project.tasks.scanVersionsReport.mustRunAfter(task)
allIdentifiers.addAll(contentSet)
if (!keyIdentifiers.compareAndSet(Collections.emptySet(), contentSet)) {
def intersection = Sets.intersection(keyIdentifiers.get(), contentSet)
keyIdentifiers.get().retainAll(intersection)
}
}
}
project.tasks.scanVersions.finalizedBy(task)
project.tasks.scanVersionsReport.mustRunAfter(task)
}
def filter(List<Version> list) {
list.removeIf {
def version = it.toString().toLowerCase()
return version.contains("rc") || version.contains("alpha") || version.contains("beta") || version.contains("-b")
return version.contains("rc") ||
version.contains("alpha") ||
version.contains("beta") ||
version.contains("-b") ||
version.contains(".m") ||
version.contains("-dev")
}
return list
}
def findMethodNames(JarFile jar, JarEntry entry) {
def stream = jar.getInputStream(entry)
def classNode = new ClassNode()
def cr = new ClassReader(stream)
cr.accept(classNode, 0)
return classNode.methods.collect { it.name }
}
RepositorySystem newRepositorySystem() {
DefaultServiceLocator locator = MavenRepositorySystemUtils.newServiceLocator()
locator.addService(RepositoryConnectorFactory.class, BasicRepositoryConnectorFactory.class)
locator.addService(TransporterFactory.class, FileTransporterFactory.class)
locator.addService(TransporterFactory.class, HttpTransporterFactory.class)
return locator.getService(RepositorySystem.class)

View File

@ -4,4 +4,6 @@ versionScan {
group = "org.apache.httpcomponents"
module = "httpclient"
versions = "[4.3,)"
legacyGroup = "commons-httpclient"
legacyModule = "commons-httpclient"
}

View File

@ -1,9 +1,9 @@
// This results in download a LOT of modules. commenting out for now...
// apply plugin: 'version-scan'
//
//versionScan {
// group = "com.amazonaws"
// module = "aws-java-sdk"
// versions = "[1.11.119,)"
//}
apply plugin: 'version-scan'
versionScan {
group = "com.amazonaws"
module = "aws-java-sdk-core"
versions = "[1.11.0,)"
}

View File

@ -4,4 +4,5 @@ versionScan {
group = "javax.jms"
module = "javax.jms-api"
versions = "[2,)"
legacyModule = "jms-api"
}

View File

@ -0,0 +1,7 @@
apply plugin: 'version-scan'
versionScan {
group = "org.mongodb"
module = "mongodb-driver-async"
versions = "[3.0,)"
}

View File

@ -4,4 +4,5 @@ versionScan {
group = "com.squareup.okhttp3"
module = "okhttp"
versions = "[3.0,)"
legacyGroup = "com.squareup.okhttp"
}

View File

@ -0,0 +1,7 @@
apply plugin: 'version-scan'
versionScan {
group = "org.apache.tomcat.embed"
module = "tomcat-embed-core"
versions = "[8.0,)"
}

View File

@ -0,0 +1,7 @@
apply plugin: 'version-scan'
versionScan {
group = "org.apache.tomcat"
module = "tomcat-catalina"
versions = "[8.0,)"
}

View File

@ -1,7 +0,0 @@
apply plugin: 'version-scan'
versionScan {
group = "javax.servlet"
module = "javax.servlet-api"
versions = "(,)"
}

View File

@ -10,6 +10,10 @@
opentracing-apache-httpclient:
- artifact: httpclient
supported_version: 4\.[3|4|5]\..*
identifying_present_classes:
- org.apache.http.conn.SchemePortResolver
- org.apache.http.config.Lookup
- org.apache.http.conn.ssl.SSLContexts
- artifact: commons-httpclient
supported_version: none
@ -17,40 +21,64 @@ opentracing-apache-httpclient:
opentracing-aws-sdk:
- artifact: aws-java-sdk
supported_version: 1\.11\..*
identifying_present_classes:
- com.amazonaws.http.client.HttpClientFactory
- com.amazonaws.http.apache.utils.ApacheUtils
- com.amazonaws.http.request.HttpRequestFactory
opentracing-cassandra-driver:
- artifact: cassandra-driver-core
supported_version: 3\.2.*
identifying_present_classes:
- com.datastax.driver.core.utils.MoreObjects
- com.datastax.driver.core.RemoteEndpointAwareNettySSLOptions
- com.datastax.driver.core.GuavaCompatibility
opentracing-web-servlet-filter:
- artifact: jetty-server
supported_version: (8\.|9\.).*
identifying_present_classes:
- artifact: tomcat_catalina
supported_version: (8\.|9\.).*
identifying_present_classes:
- org.apache.catalina.WebResource
- org.apache.catalina.webresources.TrackedInputStream
- org.apache.catalina.webresources.AbstractArchiveResource
- artifact: tomcat-embed-core
supported_version: (8\.|9\.).*
identifying_present_classes:
- org.apache.catalina.WebResource
- org.apache.catalina.webresources.TrackedInputStream
- org.apache.catalina.webresources.AbstractArchiveResource
opentracing-okhttp3:
- artifact: okhttp
supported_version: 3\..*
identifying_present_classes:
- okhttp3.Cookie
- okhttp3.ConnectionPool
- okhttp3.Headers
# For rules opentracing-jms-2_{consumer,producer}
opentracing-jms-2:
- artifact: javax.jms-api
supported_version: 2\..*
identifying_present_classes
- javax.jms.JMSContext
- javax.jms.CompletionListener
opentracing-mongo-driver:
- artifact: mongo-java-driver
supported_version: 3\..*
identifying_present_classes:
- com.mongodb.operation.AsyncReadOperation.class
- com.mongodb.client.model.MapReduceAction.class
- com.mongodb.operation.AsyncReadOperation
- com.mongodb.client.model.MapReduceAction
- check:
artifact: mongodb-driver-async
supported_version: 3\..*
identifying_present_classes:
- com.mongodb.operation.AsyncReadOperation.class
- com.mongodb.client.model.MapReduceAction.class
- com.mongodb.operation.AsyncReadOperation
- com.mongodb.client.model.MapReduceAction

View File

@ -16,7 +16,10 @@ include ':dd-java-agent:integrations:aws-sdk'
include ':dd-java-agent:integrations:cassandra'
include ':dd-java-agent:integrations:jms'
include ':dd-java-agent:integrations:mongo'
include ':dd-java-agent:integrations:mongo-async'
include ':dd-java-agent:integrations:okhttp'
include ':dd-java-agent:integrations:tomcat'
include ':dd-java-agent:integrations:tomcat-embedded'
def setBuildFile(project) {
project.buildFileName = "${project.name}.gradle"