engineyard-visualvm 0.5.0
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +5 -0
- data/Gemfile +16 -0
- data/LICENSE.txt +23 -0
- data/README.md +102 -0
- data/Rakefile +76 -0
- data/Vagrantfile +94 -0
- data/bin/ey-visualvm +9 -0
- data/cookbooks/apt/README.md +122 -0
- data/cookbooks/apt/files/default/apt-cacher +9 -0
- data/cookbooks/apt/files/default/apt-cacher.conf +144 -0
- data/cookbooks/apt/files/default/apt-proxy-v2.conf +50 -0
- data/cookbooks/apt/metadata.json +34 -0
- data/cookbooks/apt/metadata.rb +13 -0
- data/cookbooks/apt/providers/repository.rb +73 -0
- data/cookbooks/apt/recipes/cacher-client.rb +44 -0
- data/cookbooks/apt/recipes/cacher.rb +45 -0
- data/cookbooks/apt/recipes/default.rb +50 -0
- data/cookbooks/apt/resources/repository.rb +30 -0
- data/cookbooks/gems/recipes/default.rb +16 -0
- data/cookbooks/java/README.md +102 -0
- data/cookbooks/java/attributes/default.rb +29 -0
- data/cookbooks/java/files/default/java.seed +11 -0
- data/cookbooks/java/metadata.json +50 -0
- data/cookbooks/java/metadata.rb +16 -0
- data/cookbooks/java/recipes/default.rb +21 -0
- data/cookbooks/java/recipes/openjdk.rb +39 -0
- data/cookbooks/java/recipes/sun.rb +93 -0
- data/cookbooks/jruby/attributes/default.rb +2 -0
- data/cookbooks/jruby/recipes/default.rb +24 -0
- data/cookbooks/server/recipes/default.rb +9 -0
- data/cookbooks/server/templates/default/server.sh.erb +27 -0
- data/cookbooks/vagrant_main/recipes/default.rb +4 -0
- data/engineyard-visualvm.gemspec +28 -0
- data/ext/org/jruby/ext/jmx/Agent.java +169 -0
- data/ext/org/jruby/ext/jmx/JavaHome.java +7 -0
- data/ext/org/jruby/ext/jmx/RMIServerSocketFactoryImpl.java +37 -0
- data/lib/engineyard-visualvm.rb +8 -0
- data/lib/engineyard-visualvm/agent.jar +0 -0
- data/lib/engineyard-visualvm/cli.rb +205 -0
- data/lib/engineyard-visualvm/version.rb +11 -0
- data/spec/engineyard-visualvm_spec.rb +164 -0
- data/spec/spec_helper.rb +30 -0
- metadata +154 -0
@@ -0,0 +1,27 @@
|
|
1
|
+
#!/bin/bash
|
2
|
+
|
3
|
+
export PATH=/usr/local/bin:$PATH
|
4
|
+
export JAVA_OPTS=$(jruby -S ey-visualvm jvmargs)
|
5
|
+
|
6
|
+
start() {
|
7
|
+
/sbin/start-stop-daemon --start --verbose --background --make-pidfile \
|
8
|
+
--pidfile server.pid --exec /usr/local/bin/jruby --chdir $PWD \
|
9
|
+
-- -e sleep
|
10
|
+
}
|
11
|
+
|
12
|
+
stop() {
|
13
|
+
/sbin/start-stop-daemon --stop --quiet --pidfile server.pid
|
14
|
+
}
|
15
|
+
|
16
|
+
case $1 in
|
17
|
+
start)
|
18
|
+
start
|
19
|
+
;;
|
20
|
+
stop)
|
21
|
+
stop
|
22
|
+
;;
|
23
|
+
*)
|
24
|
+
start
|
25
|
+
;;
|
26
|
+
esac
|
27
|
+
|
@@ -0,0 +1,28 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
$:.push File.expand_path("../lib", __FILE__)
|
3
|
+
require "engineyard-visualvm/version"
|
4
|
+
|
5
|
+
Gem::Specification.new do |s|
|
6
|
+
s.name = "engineyard-visualvm"
|
7
|
+
s.version = EngineYard::VisualVM::VERSION
|
8
|
+
s.authors = ["Nick Sieger"]
|
9
|
+
s.email = ["nick@nicksieger.com"]
|
10
|
+
s.homepage = "https://github.com/engineyard/engineyard-visualvm"
|
11
|
+
s.summary = %q{Client and server helpers for using JMX and VisualVM with EY Cloud.}
|
12
|
+
s.description = %q{This provides a Java agent and command-line utility to enable
|
13
|
+
JMX in any Java process such that it can be accessed through a firewall,
|
14
|
+
and a VisualVM launcher aid to connect to that process through ssh.}
|
15
|
+
|
16
|
+
s.rubyforge_project = "jruby-extras"
|
17
|
+
|
18
|
+
s.files = `git ls-files`.split("\n")
|
19
|
+
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
20
|
+
s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
21
|
+
s.require_paths = ["lib"]
|
22
|
+
|
23
|
+
s.add_runtime_dependency "childprocess"
|
24
|
+
s.add_runtime_dependency "engineyard"
|
25
|
+
s.add_runtime_dependency "jruby-openssl" # engineyard gem uses ssl
|
26
|
+
s.add_runtime_dependency "ffi-ncurses" # for highline gem, dep of engineyard
|
27
|
+
s.add_development_dependency "rspec"
|
28
|
+
end
|
@@ -0,0 +1,169 @@
|
|
1
|
+
/*
|
2
|
+
* Copyright (c) 2011 Engine Yard, Inc.
|
3
|
+
* See the file LICENSE.txt included with the distribution for
|
4
|
+
* software license details.
|
5
|
+
*
|
6
|
+
* Based on CustomAgent.java found at the following URLs:
|
7
|
+
* https://blogs.oracle.com/jmxetc/entry/connecting_through_firewall_using_jmx
|
8
|
+
* https://blogs.oracle.com/jmxetc/entry/more_on_premain_and_jmx
|
9
|
+
*/
|
10
|
+
/*
|
11
|
+
* CustomAgent.java
|
12
|
+
*
|
13
|
+
* Copyright 2007, 2011 Sun Microsystems, Inc. All Rights Reserved.
|
14
|
+
*
|
15
|
+
* Redistribution and use in source and binary forms, with or without
|
16
|
+
* modification, are permitted provided that the following conditions
|
17
|
+
* are met:
|
18
|
+
*
|
19
|
+
* - Redistributions of source code must retain the above copyright
|
20
|
+
* notice, this list of conditions and the following disclaimer.
|
21
|
+
*
|
22
|
+
* - Redistributions in binary form must reproduce the above copyright
|
23
|
+
* notice, this list of conditions and the following disclaimer in the
|
24
|
+
* documentation and/or other materials provided with the distribution.
|
25
|
+
*
|
26
|
+
* - Neither the name of Sun Microsystems nor the names of its
|
27
|
+
* contributors may be used to endorse or promote products derived
|
28
|
+
* from this software without specific prior written permission.
|
29
|
+
*
|
30
|
+
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
|
31
|
+
* IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
|
32
|
+
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
33
|
+
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
34
|
+
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
35
|
+
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
36
|
+
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
37
|
+
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
38
|
+
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
39
|
+
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
40
|
+
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
41
|
+
*
|
42
|
+
* Created on Jul 25, 2007, 11:42:49 AM
|
43
|
+
*
|
44
|
+
*/
|
45
|
+
|
46
|
+
package org.jruby.ext.jmx;
|
47
|
+
|
48
|
+
import java.io.IOException;
|
49
|
+
import java.lang.management.ManagementFactory;
|
50
|
+
import java.rmi.Remote;
|
51
|
+
import java.rmi.registry.LocateRegistry;
|
52
|
+
import java.rmi.server.RMIServerSocketFactory;
|
53
|
+
import java.rmi.server.UnicastRemoteObject;
|
54
|
+
import java.util.HashMap;
|
55
|
+
import javax.management.MBeanServer;
|
56
|
+
import javax.management.remote.JMXConnectorServer;
|
57
|
+
import javax.management.remote.JMXConnectorServerFactory;
|
58
|
+
import javax.management.remote.JMXServiceURL;
|
59
|
+
import javax.management.remote.rmi.RMIConnectorServer;
|
60
|
+
|
61
|
+
import sun.jvmstat.monitor.remote.RemoteHost;
|
62
|
+
import sun.tools.jstatd.RemoteHostImpl;
|
63
|
+
import java.rmi.Naming;
|
64
|
+
|
65
|
+
public class Agent {
|
66
|
+
|
67
|
+
private static Thread cleaner;
|
68
|
+
|
69
|
+
private Agent() { }
|
70
|
+
|
71
|
+
public static void premain(String agentArgs) throws IOException {
|
72
|
+
|
73
|
+
// Ensure cryptographically strong random number generator used
|
74
|
+
// to choose the object number - see java.rmi.server.ObjID
|
75
|
+
//
|
76
|
+
System.setProperty("java.rmi.server.randomIDs", "true");
|
77
|
+
|
78
|
+
// Ensure JRuby JMX beans are available in all runtimes
|
79
|
+
System.setProperty("jruby.management.enabled", "true");
|
80
|
+
|
81
|
+
final int port = Integer.parseInt(System.getProperty("org.jruby.jmx.agent.port", "5900"));
|
82
|
+
final String hostname = System.getProperty("org.jruby.jmx.agent.hostname", "localhost");
|
83
|
+
|
84
|
+
// Make sure our RMI server knows which host we're binding to
|
85
|
+
System.setProperty("java.rmi.server.hostname", hostname);
|
86
|
+
System.setProperty("java.rmi.server.disableHttp", "true");
|
87
|
+
|
88
|
+
final RMIServerSocketFactory factory = new RMIServerSocketFactoryImpl(hostname);
|
89
|
+
|
90
|
+
LocateRegistry.createRegistry(port, null, factory);
|
91
|
+
MBeanServer mbs = ManagementFactory.getPlatformMBeanServer();
|
92
|
+
HashMap<String,Object> env = new HashMap<String,Object>();
|
93
|
+
env.put(RMIConnectorServer.RMI_SERVER_SOCKET_FACTORY_ATTRIBUTE, factory);
|
94
|
+
|
95
|
+
// Create an RMI connector server.
|
96
|
+
//
|
97
|
+
// As specified in the JMXServiceURL the RMIServer stub will be
|
98
|
+
// registered in the RMI registry running in the local host with the
|
99
|
+
// name "jmxrmi". This is the same name the out-of-the-box
|
100
|
+
// management agent uses to register the RMIServer stub too.
|
101
|
+
//
|
102
|
+
// The port specified in "service:jmx:rmi://"+hostname+":"+port
|
103
|
+
// is the second port, where RMI connection objects will be exported.
|
104
|
+
// Here we use the same port as that we choose for the RMI registry.
|
105
|
+
// The port for the RMI registry is specified in the second part
|
106
|
+
// of the URL, in "rmi://"+hostname+":"+port
|
107
|
+
//
|
108
|
+
JMXConnectorServer cs = new RMIConnectorServer(makeJMXServiceURL(hostname, port), env, mbs);
|
109
|
+
|
110
|
+
try {
|
111
|
+
// Create and register Jstatd remote host
|
112
|
+
Remote remoteHost = (Remote) Class.forName("sun.tools.jstatd.RemoteHostImpl").newInstance();
|
113
|
+
UnicastRemoteObject.exportObject(remoteHost, port, null, factory);
|
114
|
+
Naming.rebind("//"+hostname+":"+port+"/JStatRemoteHost", remoteHost);
|
115
|
+
} catch (Throwable e) {
|
116
|
+
System.err.println("Unable to start jstatd monitor: " + e.toString());
|
117
|
+
}
|
118
|
+
|
119
|
+
cs.start();
|
120
|
+
cleaner = new CleanThread(cs);
|
121
|
+
cleaner.start();
|
122
|
+
}
|
123
|
+
|
124
|
+
public static JMXServiceURL makeJMXServiceURL(String hostname, int port) throws IOException {
|
125
|
+
return new JMXServiceURL("service:jmx:rmi://"+hostname+
|
126
|
+
":"+port+"/jndi/rmi://"+hostname+":"+port+"/jmxrmi");
|
127
|
+
}
|
128
|
+
|
129
|
+
public static class CleanThread extends Thread {
|
130
|
+
private final JMXConnectorServer cs;
|
131
|
+
public CleanThread(JMXConnectorServer cs) {
|
132
|
+
super("JMX Agent Cleaner");
|
133
|
+
this.cs = cs;
|
134
|
+
setDaemon(true);
|
135
|
+
}
|
136
|
+
public void run() {
|
137
|
+
boolean loop = true;
|
138
|
+
try {
|
139
|
+
while (loop) {
|
140
|
+
final Thread[] all = new Thread[Thread.activeCount()+100];
|
141
|
+
final int count = Thread.enumerate(all);
|
142
|
+
loop = false;
|
143
|
+
for (int i=0;i<count;i++) {
|
144
|
+
final Thread t = all[i];
|
145
|
+
// daemon: skip it.
|
146
|
+
if (t.isDaemon()) continue;
|
147
|
+
// RMI Reaper: skip it.
|
148
|
+
if (t.getName().startsWith("RMI Reaper")) continue;
|
149
|
+
if (t.getName().startsWith("DestroyJavaVM")) continue;
|
150
|
+
// Non daemon, non RMI Reaper: join it, break the for
|
151
|
+
// loop, continue in the while loop (loop=true)
|
152
|
+
loop = true;
|
153
|
+
try {
|
154
|
+
t.join();
|
155
|
+
} catch (Exception ex) {
|
156
|
+
}
|
157
|
+
break;
|
158
|
+
}
|
159
|
+
}
|
160
|
+
} catch (Exception ex) {
|
161
|
+
} finally {
|
162
|
+
try {
|
163
|
+
cs.stop();
|
164
|
+
} catch (Exception ex) {
|
165
|
+
}
|
166
|
+
}
|
167
|
+
}
|
168
|
+
}
|
169
|
+
}
|
@@ -0,0 +1,37 @@
|
|
1
|
+
/*
|
2
|
+
* Copyright (c) 2011 Engine Yard, Inc.
|
3
|
+
* See the file LICENSE.txt included with the distribution for
|
4
|
+
* software license details.
|
5
|
+
*
|
6
|
+
*
|
7
|
+
* Cribbed from http://vafer.org/blog/20061010091658/
|
8
|
+
*/
|
9
|
+
|
10
|
+
package org.jruby.ext.jmx;
|
11
|
+
|
12
|
+
import java.io.IOException;
|
13
|
+
import java.net.InetAddress;
|
14
|
+
import java.net.ServerSocket;
|
15
|
+
import java.net.UnknownHostException;
|
16
|
+
import java.rmi.server.RMIServerSocketFactory;
|
17
|
+
import javax.net.ServerSocketFactory;
|
18
|
+
|
19
|
+
public class RMIServerSocketFactoryImpl implements RMIServerSocketFactory {
|
20
|
+
private final InetAddress localAddress;
|
21
|
+
|
22
|
+
public RMIServerSocketFactoryImpl(final String address) throws UnknownHostException {
|
23
|
+
localAddress = InetAddress.getByName(address);
|
24
|
+
}
|
25
|
+
|
26
|
+
public ServerSocket createServerSocket(final int port) throws IOException {
|
27
|
+
return ServerSocketFactory.getDefault().createServerSocket(port, 0, localAddress);
|
28
|
+
}
|
29
|
+
|
30
|
+
public boolean equals(Object obj) {
|
31
|
+
return obj != null && obj.getClass().equals(getClass());
|
32
|
+
}
|
33
|
+
|
34
|
+
public int hashCode() {
|
35
|
+
return RMIServerSocketFactoryImpl.class.hashCode();
|
36
|
+
}
|
37
|
+
}
|
Binary file
|
@@ -0,0 +1,205 @@
|
|
1
|
+
#--
|
2
|
+
# Copyright (c) 2011 Engine Yard, Inc.
|
3
|
+
# See the file LICENSE.txt included with the distribution for
|
4
|
+
# software license details.
|
5
|
+
#++
|
6
|
+
|
7
|
+
require "thor"
|
8
|
+
require "childprocess"
|
9
|
+
require "socket"
|
10
|
+
require "engineyard"
|
11
|
+
require "engineyard/cli"
|
12
|
+
require "engineyard/thor"
|
13
|
+
|
14
|
+
module EngineYard
|
15
|
+
module VisualVM
|
16
|
+
module Helpers
|
17
|
+
def self.port_available?(port)
|
18
|
+
begin
|
19
|
+
tcps = TCPServer.new("127.0.0.1", port)
|
20
|
+
true
|
21
|
+
rescue Errno::EADDRINUSE
|
22
|
+
false
|
23
|
+
ensure
|
24
|
+
tcps.close if tcps
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
STARTING_PORT = 5900
|
29
|
+
|
30
|
+
def self.next_free_port(start = STARTING_PORT)
|
31
|
+
(start...start+100).each do |i|
|
32
|
+
return i if port_available?(i)
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
def environment
|
37
|
+
@environment ||= begin
|
38
|
+
fetch_environment(options[:environment], options[:account]).tap {|env|
|
39
|
+
@user = env.username
|
40
|
+
@host = fetch_public_ip(env)
|
41
|
+
}
|
42
|
+
rescue EY::Error
|
43
|
+
raise if options[:environment]
|
44
|
+
nil
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
def user
|
49
|
+
@user
|
50
|
+
end
|
51
|
+
|
52
|
+
def ssh?
|
53
|
+
environment || (host && user) || options[:ssh] || options[:socks]
|
54
|
+
end
|
55
|
+
|
56
|
+
def socks_proxy?
|
57
|
+
options[:socks]
|
58
|
+
end
|
59
|
+
|
60
|
+
def ssh_host
|
61
|
+
user ? "#{user}@#{host}" : host
|
62
|
+
end
|
63
|
+
|
64
|
+
def host
|
65
|
+
@host ||= begin
|
66
|
+
match = /(.*)?@(.*)/.match options[:host]
|
67
|
+
if match
|
68
|
+
@user = match[1]
|
69
|
+
match[2]
|
70
|
+
else
|
71
|
+
@user = nil
|
72
|
+
options[:host]
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
def next_free_port
|
78
|
+
Helpers.next_free_port(port)
|
79
|
+
end
|
80
|
+
|
81
|
+
def port
|
82
|
+
@port ||= Numeric === options[:port] && options[:port] || STARTING_PORT
|
83
|
+
end
|
84
|
+
|
85
|
+
def jvm_arguments
|
86
|
+
tools_jar = find_tools_jar
|
87
|
+
args = "-Dorg.jruby.jmx.agent.port=#{next_free_port} -javaagent:#{agent_jar_path}"
|
88
|
+
args = "-Dorg.jruby.jmx.agent.hostname=#{host} #{args}" if host != "localhost"
|
89
|
+
args = "-Xbootclasspath/a:#{tools_jar} #{args}" if tools_jar
|
90
|
+
args
|
91
|
+
end
|
92
|
+
|
93
|
+
def jmx_service_url
|
94
|
+
"service:jmx:rmi://#{host}:#{port}/jndi/rmi://#{host}:#{port}/jmxrmi"
|
95
|
+
end
|
96
|
+
|
97
|
+
def find_executable?(exe)
|
98
|
+
ENV['PATH'].split(File::PATH_SEPARATOR).detect do |path|
|
99
|
+
File.exist?(File.join(path, exe))
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
103
|
+
def agent_jar_path
|
104
|
+
File.expand_path('../agent.jar', __FILE__)
|
105
|
+
end
|
106
|
+
|
107
|
+
def find_tools_jar
|
108
|
+
java_home = `java -classpath #{agent_jar_path} org.jruby.ext.jmx.agent.JavaHome`
|
109
|
+
[File.expand_path('./lib/tools.jar', java_home),
|
110
|
+
File.expand_path('../lib/tools.jar', java_home)].detect do |path|
|
111
|
+
File.readable?(path)
|
112
|
+
end
|
113
|
+
end
|
114
|
+
|
115
|
+
# Return the public IP assigned to an environment (which may or
|
116
|
+
# may not be a booted cluster of instances) Displays error and
|
117
|
+
# exits if no public IP assigned to the environment
|
118
|
+
def fetch_public_ip(environment)
|
119
|
+
unless environment.load_balancer_ip_address
|
120
|
+
warn "#{environment.account.name}/#{environment.name} has no assigned public IP address."
|
121
|
+
end
|
122
|
+
|
123
|
+
environment.load_balancer_ip_address
|
124
|
+
end
|
125
|
+
end
|
126
|
+
|
127
|
+
class CLI < Thor
|
128
|
+
include EY::UtilityMethods
|
129
|
+
include Helpers
|
130
|
+
|
131
|
+
class_option :host, :aliases => ["-H"], :default => "localhost",
|
132
|
+
:desc => "Host or IP where the JMX agent runs"
|
133
|
+
class_option :port, :aliases => ["-p"], :type => :numeric, :default => STARTING_PORT.to_s,
|
134
|
+
:desc => "Port where the JMX agent runs"
|
135
|
+
|
136
|
+
desc "jvmargs", "Print the arguments to be passed to the server JVM"
|
137
|
+
def jvmargs
|
138
|
+
puts jvm_arguments
|
139
|
+
end
|
140
|
+
|
141
|
+
desc "url", "Print the connection URL for the JMX server process"
|
142
|
+
def url
|
143
|
+
puts jmx_service_url
|
144
|
+
end
|
145
|
+
|
146
|
+
desc "version", "Show version"
|
147
|
+
def version
|
148
|
+
puts "ey-visualvm version #{EngineYard::VisualVM::VERSION}"
|
149
|
+
end
|
150
|
+
|
151
|
+
desc "start", "Launch VisualVM to connect to the server.\nUse either the environment/account or host/port options."
|
152
|
+
method_option :ssh, :type => :boolean, :desc => "Force VisualVM to connect through an ssh tunnel"
|
153
|
+
method_option :socks, :type => :boolean, :desc => "Force VisualVM to connect through a SOCKS proxy"
|
154
|
+
method_option :environment, :aliases => ["-e"], :desc => "Environment containing the IP to which to resolve", :type => :string
|
155
|
+
method_option :account, :aliases => ["-c"], :desc => "Name of the account where the environment is found"
|
156
|
+
def start
|
157
|
+
unless find_executable?("jvisualvm")
|
158
|
+
warn "Could not find \`jvisualvm\'; do you need to install the JDK?"
|
159
|
+
exit 1
|
160
|
+
end
|
161
|
+
|
162
|
+
visualvm_args = []
|
163
|
+
|
164
|
+
if ssh?
|
165
|
+
ssh_dest = ssh_host
|
166
|
+
|
167
|
+
if socks_proxy?
|
168
|
+
proxy_port = next_free_port
|
169
|
+
visualvm_args += ["-J-Dnetbeans.system_socks_proxy=localhost:#{proxy_port}", "-J-Djava.net.useSystemProxies=true"]
|
170
|
+
@ssh_process = ChildProcess.build("ssh", "-ND", proxy_port.to_s, ssh_dest)
|
171
|
+
else
|
172
|
+
server_host, server_port = host, port
|
173
|
+
@host, @port = "localhost", next_free_port
|
174
|
+
@ssh_process = ChildProcess.build("ssh", "-NL", "#{@port}:#{@host}:#{server_port}", "#{ssh_dest}")
|
175
|
+
end
|
176
|
+
|
177
|
+
@ssh_process.start
|
178
|
+
end
|
179
|
+
|
180
|
+
visualvm_args += ["--openjmx", jmx_service_url.to_s]
|
181
|
+
visualvm = ChildProcess.build("jvisualvm", *visualvm_args)
|
182
|
+
visualvm.start
|
183
|
+
|
184
|
+
loop do
|
185
|
+
visualvm.exited? && break
|
186
|
+
sleep 1
|
187
|
+
end
|
188
|
+
|
189
|
+
@ssh_process.stop if @ssh_process
|
190
|
+
rescue EY::Error => e
|
191
|
+
warn e.message
|
192
|
+
exit 2
|
193
|
+
end
|
194
|
+
|
195
|
+
def help(task = nil, *args)
|
196
|
+
unless task
|
197
|
+
puts "usage: ey-visualvm <task> [options|arguments]"
|
198
|
+
puts "Make JMX and VisualVM more accessible to your server-side JVM."
|
199
|
+
puts
|
200
|
+
end
|
201
|
+
super
|
202
|
+
end
|
203
|
+
end
|
204
|
+
end
|
205
|
+
end
|