summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorStephen Wong <stephen.kf.wong@gmail.com>2018-08-19 07:17:28 +0000
committerGerrit Code Review <gerrit@opnfv.org>2018-08-19 07:17:28 +0000
commitd24dce594859ece995e2775013951a3e12258d95 (patch)
tree5b0775bb55746c366b67bc67114e98cf7a8283a3
parent6fcc32c8d357c1f1e6b4aa667df0c1aa2c87d6f2 (diff)
parente904c8e2d35cb16f744a0de3b20466ad3befa36d (diff)
Merge "Implement initial Jmeter master/slave containers"
-rwxr-xr-xclover/tools/jmeter/build_master.sh16
-rwxr-xr-xclover/tools/jmeter/build_slave.sh16
-rw-r--r--clover/tools/jmeter/jmeter-master/Dockerfile29
-rwxr-xr-xclover/tools/jmeter/jmeter-master/grpc/build_proto.sh11
-rw-r--r--clover/tools/jmeter/jmeter-master/grpc/jmeter.proto43
-rw-r--r--clover/tools/jmeter/jmeter-master/grpc/jmeter_pb2.py291
-rw-r--r--clover/tools/jmeter/jmeter-master/grpc/jmeter_pb2_grpc.py80
-rw-r--r--clover/tools/jmeter/jmeter-master/grpc/jmeter_server.py118
-rwxr-xr-xclover/tools/jmeter/jmeter-master/process/grpc_process.sh11
-rw-r--r--clover/tools/jmeter/jmeter-master/tests/jmx.template135
-rw-r--r--clover/tools/jmeter/jmeter-slave/Dockerfile27
-rw-r--r--clover/tools/jmeter/rmi_keystore.jksbin0 -> 2190 bytes
-rw-r--r--clover/tools/jmeter/yaml/manifest.template45
-rw-r--r--clover/tools/jmeter/yaml/render_master.py67
-rw-r--r--clover/tools/jmeter/yaml/render_slave.py67
15 files changed, 956 insertions, 0 deletions
diff --git a/clover/tools/jmeter/build_master.sh b/clover/tools/jmeter/build_master.sh
new file mode 100755
index 0000000..5c5459a
--- /dev/null
+++ b/clover/tools/jmeter/build_master.sh
@@ -0,0 +1,16 @@
+#!/bin/bash
+#
+# Copyright (c) Authors of Clover
+#
+# All rights reserved. This program and the accompanying materials
+# are made available under the terms of the Apache License, Version 2.0
+# which accompanies this distribution, and is available at
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+
+IMAGE_PATH=${IMAGE_PATH:-"localhost:5000"}
+IMAGE_NAME=${IMAGE_NAME:-"clover-jmeter-master"}
+
+docker build -f jmeter-master/Dockerfile -t $IMAGE_NAME .
+docker tag $IMAGE_NAME $IMAGE_PATH/$IMAGE_NAME
+docker push $IMAGE_PATH/$IMAGE_NAME
diff --git a/clover/tools/jmeter/build_slave.sh b/clover/tools/jmeter/build_slave.sh
new file mode 100755
index 0000000..1651c55
--- /dev/null
+++ b/clover/tools/jmeter/build_slave.sh
@@ -0,0 +1,16 @@
+#!/bin/bash
+#
+# Copyright (c) Authors of Clover
+#
+# All rights reserved. This program and the accompanying materials
+# are made available under the terms of the Apache License, Version 2.0
+# which accompanies this distribution, and is available at
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+
+IMAGE_PATH=${IMAGE_PATH:-"localhost:5000"}
+IMAGE_NAME=${IMAGE_NAME:-"clover-jmeter-slave"}
+
+docker build -f jmeter-slave/Dockerfile -t $IMAGE_NAME .
+docker tag $IMAGE_NAME $IMAGE_PATH/$IMAGE_NAME
+docker push $IMAGE_PATH/$IMAGE_NAME
diff --git a/clover/tools/jmeter/jmeter-master/Dockerfile b/clover/tools/jmeter/jmeter-master/Dockerfile
new file mode 100644
index 0000000..da0e474
--- /dev/null
+++ b/clover/tools/jmeter/jmeter-master/Dockerfile
@@ -0,0 +1,29 @@
+# Copyright (c) Authors of Clover
+#
+# All rights reserved. This program and the accompanying materials
+# are made available under the terms of the Apache License, Version 2.0
+# which accompanies this distribution, and is available at
+# http://www.apache.org/licenses/LICENSE-2.0
+
+FROM java:8
+
+RUN wget http://apache.mirrors.hoobly.com//jmeter/binaries/apache-jmeter-4.0.tgz
+RUN tar -xvzf apache-jmeter-4.0.tgz
+RUN rm apache-jmeter-4.0.tgz
+RUN mv apache-jmeter-4.0 /jmeter
+ENV JMETER_HOME /jmeter
+ENV PATH $JMETER_HOME/bin:$PATH
+COPY rmi_keystore.jks $JMETER_HOME/bin
+
+RUN apt update && apt install -y python-setuptools python-dev python-pip
+RUN python -m pip install --upgrade pip
+RUN python -m pip install enum34 futures cython
+RUN python -m pip install grpcio protobuf jinja2
+
+WORKDIR /jmeter/bin
+
+COPY jmeter-master/process process
+COPY jmeter-master/grpc grpc
+COPY jmeter-master/tests tests
+
+CMD ./process/grpc_process.sh no_init
diff --git a/clover/tools/jmeter/jmeter-master/grpc/build_proto.sh b/clover/tools/jmeter/jmeter-master/grpc/build_proto.sh
new file mode 100755
index 0000000..52dfd0a
--- /dev/null
+++ b/clover/tools/jmeter/jmeter-master/grpc/build_proto.sh
@@ -0,0 +1,11 @@
+#!/bin/bash
+#
+# Copyright (c) Authors of Clover
+#
+# All rights reserved. This program and the accompanying materials
+# are made available under the terms of the Apache License, Version 2.0
+# which accompanies this distribution, and is available at
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+
+python -m grpc_tools.protoc -I./ --python_out=. --grpc_python_out=. jmeter.proto
diff --git a/clover/tools/jmeter/jmeter-master/grpc/jmeter.proto b/clover/tools/jmeter/jmeter-master/grpc/jmeter.proto
new file mode 100644
index 0000000..7213faa
--- /dev/null
+++ b/clover/tools/jmeter/jmeter-master/grpc/jmeter.proto
@@ -0,0 +1,43 @@
+// Copyright (c) Authors of Clover
+//
+// All rights reserved. This program and the accompanying materials
+// are made available under the terms of the Apache License, Version 2.0
+// which accompanies this distribution, and is available at
+// http://www.apache.org/licenses/LICENSE-2.0
+
+syntax = "proto3";
+
+package jmeter;
+
+// The controller service definition.
+service Controller {
+
+ rpc GenTest (ConfigJmeter) returns (JmeterReply) {}
+ rpc StartTest (TestParams) returns (JmeterReply) {}
+ rpc GetResults (JResults) returns (JmeterReply) {}
+}
+
+message TestParams {
+ string num_slaves = 1;
+ string test_plan = 2;
+ string slave_ips = 3;
+}
+
+message ConfigJmeter {
+ string url_list = 1;
+ string num_threads = 2;
+ string url_names = 3;
+ string url_protocols = 4;
+ string url_methods = 5;
+ string loops = 6;
+ string ramp_time = 7;
+}
+
+message JmeterReply {
+ string message = 1;
+}
+
+message JResults {
+ string r_format = 1;
+ string r_file = 2;
+}
diff --git a/clover/tools/jmeter/jmeter-master/grpc/jmeter_pb2.py b/clover/tools/jmeter/jmeter-master/grpc/jmeter_pb2.py
new file mode 100644
index 0000000..e4a75fd
--- /dev/null
+++ b/clover/tools/jmeter/jmeter-master/grpc/jmeter_pb2.py
@@ -0,0 +1,291 @@
+# Generated by the protocol buffer compiler. DO NOT EDIT!
+# source: jmeter.proto
+
+import sys
+_b=sys.version_info[0]<3 and (lambda x:x) or (lambda x:x.encode('latin1'))
+from google.protobuf import descriptor as _descriptor
+from google.protobuf import message as _message
+from google.protobuf import reflection as _reflection
+from google.protobuf import symbol_database as _symbol_database
+from google.protobuf import descriptor_pb2
+# @@protoc_insertion_point(imports)
+
+_sym_db = _symbol_database.Default()
+
+
+
+
+DESCRIPTOR = _descriptor.FileDescriptor(
+ name='jmeter.proto',
+ package='jmeter',
+ syntax='proto3',
+ serialized_pb=_b('\n\x0cjmeter.proto\x12\x06jmeter\"F\n\nTestParams\x12\x12\n\nnum_slaves\x18\x01 \x01(\t\x12\x11\n\ttest_plan\x18\x02 \x01(\t\x12\x11\n\tslave_ips\x18\x03 \x01(\t\"\x96\x01\n\x0c\x43onfigJmeter\x12\x10\n\x08url_list\x18\x01 \x01(\t\x12\x13\n\x0bnum_threads\x18\x02 \x01(\t\x12\x11\n\turl_names\x18\x03 \x01(\t\x12\x15\n\rurl_protocols\x18\x04 \x01(\t\x12\x13\n\x0burl_methods\x18\x05 \x01(\t\x12\r\n\x05loops\x18\x06 \x01(\t\x12\x11\n\tramp_time\x18\x07 \x01(\t\"\x1e\n\x0bJmeterReply\x12\x0f\n\x07message\x18\x01 \x01(\t\",\n\x08JResults\x12\x10\n\x08r_format\x18\x01 \x01(\t\x12\x0e\n\x06r_file\x18\x02 \x01(\t2\xb3\x01\n\nController\x12\x36\n\x07GenTest\x12\x14.jmeter.ConfigJmeter\x1a\x13.jmeter.JmeterReply\"\x00\x12\x36\n\tStartTest\x12\x12.jmeter.TestParams\x1a\x13.jmeter.JmeterReply\"\x00\x12\x35\n\nGetResults\x12\x10.jmeter.JResults\x1a\x13.jmeter.JmeterReply\"\x00\x62\x06proto3')
+)
+
+
+
+
+_TESTPARAMS = _descriptor.Descriptor(
+ name='TestParams',
+ full_name='jmeter.TestParams',
+ filename=None,
+ file=DESCRIPTOR,
+ containing_type=None,
+ fields=[
+ _descriptor.FieldDescriptor(
+ name='num_slaves', full_name='jmeter.TestParams.num_slaves', index=0,
+ number=1, type=9, cpp_type=9, label=1,
+ has_default_value=False, default_value=_b("").decode('utf-8'),
+ message_type=None, enum_type=None, containing_type=None,
+ is_extension=False, extension_scope=None,
+ options=None, file=DESCRIPTOR),
+ _descriptor.FieldDescriptor(
+ name='test_plan', full_name='jmeter.TestParams.test_plan', index=1,
+ number=2, type=9, cpp_type=9, label=1,
+ has_default_value=False, default_value=_b("").decode('utf-8'),
+ message_type=None, enum_type=None, containing_type=None,
+ is_extension=False, extension_scope=None,
+ options=None, file=DESCRIPTOR),
+ _descriptor.FieldDescriptor(
+ name='slave_ips', full_name='jmeter.TestParams.slave_ips', index=2,
+ number=3, type=9, cpp_type=9, label=1,
+ has_default_value=False, default_value=_b("").decode('utf-8'),
+ message_type=None, enum_type=None, containing_type=None,
+ is_extension=False, extension_scope=None,
+ options=None, file=DESCRIPTOR),
+ ],
+ extensions=[
+ ],
+ nested_types=[],
+ enum_types=[
+ ],
+ options=None,
+ is_extendable=False,
+ syntax='proto3',
+ extension_ranges=[],
+ oneofs=[
+ ],
+ serialized_start=24,
+ serialized_end=94,
+)
+
+
+_CONFIGJMETER = _descriptor.Descriptor(
+ name='ConfigJmeter',
+ full_name='jmeter.ConfigJmeter',
+ filename=None,
+ file=DESCRIPTOR,
+ containing_type=None,
+ fields=[
+ _descriptor.FieldDescriptor(
+ name='url_list', full_name='jmeter.ConfigJmeter.url_list', index=0,
+ number=1, type=9, cpp_type=9, label=1,
+ has_default_value=False, default_value=_b("").decode('utf-8'),
+ message_type=None, enum_type=None, containing_type=None,
+ is_extension=False, extension_scope=None,
+ options=None, file=DESCRIPTOR),
+ _descriptor.FieldDescriptor(
+ name='num_threads', full_name='jmeter.ConfigJmeter.num_threads', index=1,
+ number=2, type=9, cpp_type=9, label=1,
+ has_default_value=False, default_value=_b("").decode('utf-8'),
+ message_type=None, enum_type=None, containing_type=None,
+ is_extension=False, extension_scope=None,
+ options=None, file=DESCRIPTOR),
+ _descriptor.FieldDescriptor(
+ name='url_names', full_name='jmeter.ConfigJmeter.url_names', index=2,
+ number=3, type=9, cpp_type=9, label=1,
+ has_default_value=False, default_value=_b("").decode('utf-8'),
+ message_type=None, enum_type=None, containing_type=None,
+ is_extension=False, extension_scope=None,
+ options=None, file=DESCRIPTOR),
+ _descriptor.FieldDescriptor(
+ name='url_protocols', full_name='jmeter.ConfigJmeter.url_protocols', index=3,
+ number=4, type=9, cpp_type=9, label=1,
+ has_default_value=False, default_value=_b("").decode('utf-8'),
+ message_type=None, enum_type=None, containing_type=None,
+ is_extension=False, extension_scope=None,
+ options=None, file=DESCRIPTOR),
+ _descriptor.FieldDescriptor(
+ name='url_methods', full_name='jmeter.ConfigJmeter.url_methods', index=4,
+ number=5, type=9, cpp_type=9, label=1,
+ has_default_value=False, default_value=_b("").decode('utf-8'),
+ message_type=None, enum_type=None, containing_type=None,
+ is_extension=False, extension_scope=None,
+ options=None, file=DESCRIPTOR),
+ _descriptor.FieldDescriptor(
+ name='loops', full_name='jmeter.ConfigJmeter.loops', index=5,
+ number=6, type=9, cpp_type=9, label=1,
+ has_default_value=False, default_value=_b("").decode('utf-8'),
+ message_type=None, enum_type=None, containing_type=None,
+ is_extension=False, extension_scope=None,
+ options=None, file=DESCRIPTOR),
+ _descriptor.FieldDescriptor(
+ name='ramp_time', full_name='jmeter.ConfigJmeter.ramp_time', index=6,
+ number=7, type=9, cpp_type=9, label=1,
+ has_default_value=False, default_value=_b("").decode('utf-8'),
+ message_type=None, enum_type=None, containing_type=None,
+ is_extension=False, extension_scope=None,
+ options=None, file=DESCRIPTOR),
+ ],
+ extensions=[
+ ],
+ nested_types=[],
+ enum_types=[
+ ],
+ options=None,
+ is_extendable=False,
+ syntax='proto3',
+ extension_ranges=[],
+ oneofs=[
+ ],
+ serialized_start=97,
+ serialized_end=247,
+)
+
+
+_JMETERREPLY = _descriptor.Descriptor(
+ name='JmeterReply',
+ full_name='jmeter.JmeterReply',
+ filename=None,
+ file=DESCRIPTOR,
+ containing_type=None,
+ fields=[
+ _descriptor.FieldDescriptor(
+ name='message', full_name='jmeter.JmeterReply.message', index=0,
+ number=1, type=9, cpp_type=9, label=1,
+ has_default_value=False, default_value=_b("").decode('utf-8'),
+ message_type=None, enum_type=None, containing_type=None,
+ is_extension=False, extension_scope=None,
+ options=None, file=DESCRIPTOR),
+ ],
+ extensions=[
+ ],
+ nested_types=[],
+ enum_types=[
+ ],
+ options=None,
+ is_extendable=False,
+ syntax='proto3',
+ extension_ranges=[],
+ oneofs=[
+ ],
+ serialized_start=249,
+ serialized_end=279,
+)
+
+
+_JRESULTS = _descriptor.Descriptor(
+ name='JResults',
+ full_name='jmeter.JResults',
+ filename=None,
+ file=DESCRIPTOR,
+ containing_type=None,
+ fields=[
+ _descriptor.FieldDescriptor(
+ name='r_format', full_name='jmeter.JResults.r_format', index=0,
+ number=1, type=9, cpp_type=9, label=1,
+ has_default_value=False, default_value=_b("").decode('utf-8'),
+ message_type=None, enum_type=None, containing_type=None,
+ is_extension=False, extension_scope=None,
+ options=None, file=DESCRIPTOR),
+ _descriptor.FieldDescriptor(
+ name='r_file', full_name='jmeter.JResults.r_file', index=1,
+ number=2, type=9, cpp_type=9, label=1,
+ has_default_value=False, default_value=_b("").decode('utf-8'),
+ message_type=None, enum_type=None, containing_type=None,
+ is_extension=False, extension_scope=None,
+ options=None, file=DESCRIPTOR),
+ ],
+ extensions=[
+ ],
+ nested_types=[],
+ enum_types=[
+ ],
+ options=None,
+ is_extendable=False,
+ syntax='proto3',
+ extension_ranges=[],
+ oneofs=[
+ ],
+ serialized_start=281,
+ serialized_end=325,
+)
+
+DESCRIPTOR.message_types_by_name['TestParams'] = _TESTPARAMS
+DESCRIPTOR.message_types_by_name['ConfigJmeter'] = _CONFIGJMETER
+DESCRIPTOR.message_types_by_name['JmeterReply'] = _JMETERREPLY
+DESCRIPTOR.message_types_by_name['JResults'] = _JRESULTS
+_sym_db.RegisterFileDescriptor(DESCRIPTOR)
+
+TestParams = _reflection.GeneratedProtocolMessageType('TestParams', (_message.Message,), dict(
+ DESCRIPTOR = _TESTPARAMS,
+ __module__ = 'jmeter_pb2'
+ # @@protoc_insertion_point(class_scope:jmeter.TestParams)
+ ))
+_sym_db.RegisterMessage(TestParams)
+
+ConfigJmeter = _reflection.GeneratedProtocolMessageType('ConfigJmeter', (_message.Message,), dict(
+ DESCRIPTOR = _CONFIGJMETER,
+ __module__ = 'jmeter_pb2'
+ # @@protoc_insertion_point(class_scope:jmeter.ConfigJmeter)
+ ))
+_sym_db.RegisterMessage(ConfigJmeter)
+
+JmeterReply = _reflection.GeneratedProtocolMessageType('JmeterReply', (_message.Message,), dict(
+ DESCRIPTOR = _JMETERREPLY,
+ __module__ = 'jmeter_pb2'
+ # @@protoc_insertion_point(class_scope:jmeter.JmeterReply)
+ ))
+_sym_db.RegisterMessage(JmeterReply)
+
+JResults = _reflection.GeneratedProtocolMessageType('JResults', (_message.Message,), dict(
+ DESCRIPTOR = _JRESULTS,
+ __module__ = 'jmeter_pb2'
+ # @@protoc_insertion_point(class_scope:jmeter.JResults)
+ ))
+_sym_db.RegisterMessage(JResults)
+
+
+
+_CONTROLLER = _descriptor.ServiceDescriptor(
+ name='Controller',
+ full_name='jmeter.Controller',
+ file=DESCRIPTOR,
+ index=0,
+ options=None,
+ serialized_start=328,
+ serialized_end=507,
+ methods=[
+ _descriptor.MethodDescriptor(
+ name='GenTest',
+ full_name='jmeter.Controller.GenTest',
+ index=0,
+ containing_service=None,
+ input_type=_CONFIGJMETER,
+ output_type=_JMETERREPLY,
+ options=None,
+ ),
+ _descriptor.MethodDescriptor(
+ name='StartTest',
+ full_name='jmeter.Controller.StartTest',
+ index=1,
+ containing_service=None,
+ input_type=_TESTPARAMS,
+ output_type=_JMETERREPLY,
+ options=None,
+ ),
+ _descriptor.MethodDescriptor(
+ name='GetResults',
+ full_name='jmeter.Controller.GetResults',
+ index=2,
+ containing_service=None,
+ input_type=_JRESULTS,
+ output_type=_JMETERREPLY,
+ options=None,
+ ),
+])
+_sym_db.RegisterServiceDescriptor(_CONTROLLER)
+
+DESCRIPTOR.services_by_name['Controller'] = _CONTROLLER
+
+# @@protoc_insertion_point(module_scope)
diff --git a/clover/tools/jmeter/jmeter-master/grpc/jmeter_pb2_grpc.py b/clover/tools/jmeter/jmeter-master/grpc/jmeter_pb2_grpc.py
new file mode 100644
index 0000000..4df110d
--- /dev/null
+++ b/clover/tools/jmeter/jmeter-master/grpc/jmeter_pb2_grpc.py
@@ -0,0 +1,80 @@
+# Generated by the gRPC Python protocol compiler plugin. DO NOT EDIT!
+import grpc
+
+import jmeter_pb2 as jmeter__pb2
+
+
+class ControllerStub(object):
+ """The controller service definition.
+ """
+
+ def __init__(self, channel):
+ """Constructor.
+
+ Args:
+ channel: A grpc.Channel.
+ """
+ self.GenTest = channel.unary_unary(
+ '/jmeter.Controller/GenTest',
+ request_serializer=jmeter__pb2.ConfigJmeter.SerializeToString,
+ response_deserializer=jmeter__pb2.JmeterReply.FromString,
+ )
+ self.StartTest = channel.unary_unary(
+ '/jmeter.Controller/StartTest',
+ request_serializer=jmeter__pb2.TestParams.SerializeToString,
+ response_deserializer=jmeter__pb2.JmeterReply.FromString,
+ )
+ self.GetResults = channel.unary_unary(
+ '/jmeter.Controller/GetResults',
+ request_serializer=jmeter__pb2.JResults.SerializeToString,
+ response_deserializer=jmeter__pb2.JmeterReply.FromString,
+ )
+
+
+class ControllerServicer(object):
+ """The controller service definition.
+ """
+
+ def GenTest(self, request, context):
+ # missing associated documentation comment in .proto file
+ pass
+ context.set_code(grpc.StatusCode.UNIMPLEMENTED)
+ context.set_details('Method not implemented!')
+ raise NotImplementedError('Method not implemented!')
+
+ def StartTest(self, request, context):
+ # missing associated documentation comment in .proto file
+ pass
+ context.set_code(grpc.StatusCode.UNIMPLEMENTED)
+ context.set_details('Method not implemented!')
+ raise NotImplementedError('Method not implemented!')
+
+ def GetResults(self, request, context):
+ # missing associated documentation comment in .proto file
+ pass
+ context.set_code(grpc.StatusCode.UNIMPLEMENTED)
+ context.set_details('Method not implemented!')
+ raise NotImplementedError('Method not implemented!')
+
+
+def add_ControllerServicer_to_server(servicer, server):
+ rpc_method_handlers = {
+ 'GenTest': grpc.unary_unary_rpc_method_handler(
+ servicer.GenTest,
+ request_deserializer=jmeter__pb2.ConfigJmeter.FromString,
+ response_serializer=jmeter__pb2.JmeterReply.SerializeToString,
+ ),
+ 'StartTest': grpc.unary_unary_rpc_method_handler(
+ servicer.StartTest,
+ request_deserializer=jmeter__pb2.TestParams.FromString,
+ response_serializer=jmeter__pb2.JmeterReply.SerializeToString,
+ ),
+ 'GetResults': grpc.unary_unary_rpc_method_handler(
+ servicer.GetResults,
+ request_deserializer=jmeter__pb2.JResults.FromString,
+ response_serializer=jmeter__pb2.JmeterReply.SerializeToString,
+ ),
+ }
+ generic_handler = grpc.method_handlers_generic_handler(
+ 'jmeter.Controller', rpc_method_handlers)
+ server.add_generic_rpc_handlers((generic_handler,))
diff --git a/clover/tools/jmeter/jmeter-master/grpc/jmeter_server.py b/clover/tools/jmeter/jmeter-master/grpc/jmeter_server.py
new file mode 100644
index 0000000..cef180c
--- /dev/null
+++ b/clover/tools/jmeter/jmeter-master/grpc/jmeter_server.py
@@ -0,0 +1,118 @@
+# Copyright (c) Authors of Clover
+#
+# All rights reserved. This program and the accompanying materials
+# are made available under the terms of the Apache License, Version 2.0
+# which accompanies this distribution, and is available at
+# http://www.apache.org/licenses/LICENSE-2.0
+
+from concurrent import futures
+from jinja2 import Template
+from urlparse import urlparse
+import time
+import sys
+import grpc
+import subprocess
+import pickle
+import logging
+import jmeter_pb2
+import jmeter_pb2_grpc
+
+
+_ONE_DAY_IN_SECONDS = 60 * 60 * 24
+GRPC_PORT = '[::]:50054'
+
+
+class Controller(jmeter_pb2_grpc.ControllerServicer):
+
+ def __init__(self, init_jmeter):
+ logging.basicConfig(filename='jmeter_server.log',
+ level=logging.DEBUG)
+ self.jmeter = 0
+ if init_jmeter == 'init':
+ print('init test')
+
+ def GenTest(self, r, context):
+ try:
+ out_file = 'tests/test.jmx'
+ template_file = 'tests/jmx.template'
+ unames = pickle.loads(r.url_names)
+ umethods = pickle.loads(r.url_methods)
+ ulist = []
+ for url in pickle.loads(r.url_list):
+ u = urlparse(url)
+ d = {}
+ d['domain'] = u.hostname
+ if u.port:
+ d['port'] = u.port
+ else:
+ d['port'] = 80
+ if u.path == '':
+ d['path'] = '/'
+ else:
+ d['path'] = u.path
+ ulist.append(d)
+
+ with open(template_file) as f:
+ tmpl = Template(f.read())
+ output = tmpl.render(
+ num_threads=r.num_threads,
+ url_names=unames,
+ url_methods=umethods,
+ ramp_time=r.ramp_time,
+ loops=r.loops,
+ url_list=ulist
+ )
+ with open(out_file, "wb") as fh:
+ fh.write(output)
+ msg = 'Generated test plan'
+ except Exception as e:
+ logging.debug(e)
+ msg = "Failed to generate test plan"
+ return jmeter_pb2.JmeterReply(message=msg)
+
+ def StartTest(self, r, context):
+ try:
+ if r.num_slaves == '0':
+ self.jmeter = subprocess.Popen(
+ ["jmeter", "-n", "-t", "tests/test.jmx", "-l",
+ "default.jtl"], shell=False)
+ else:
+ slave_arg = "-R" + r.slave_ips
+ self.jmeter = subprocess.Popen(
+ ["jmeter", "-n", "-t", "tests/test.jmx", slave_arg, "-l",
+ "default.jtl"], shell=False)
+ msg = "Started jmeter on pid: {}".format(self.jmeter.pid)
+ except Exception as e:
+ logging.debug(e)
+ msg = e
+ return jmeter_pb2.JmeterReply(message=msg)
+
+ def GetResults(self, r, context):
+ try:
+ if r.r_file == 'log':
+ r_file = 'jmeter.log'
+ else:
+ r_file = 'default.jtl'
+ f = open(r_file, 'r')
+ msg = "Retrieved all results\n" + f.read()
+ except Exception as e:
+ logging.debug(e)
+ msg = "Failed to retrieve results"
+ return jmeter_pb2.JmeterReply(message=msg)
+
+
+def serve(init_jmeter):
+ server = grpc.server(futures.ThreadPoolExecutor(max_workers=10))
+ jmeter_pb2_grpc.add_ControllerServicer_to_server(
+ Controller(init_jmeter), server)
+ server.add_insecure_port(GRPC_PORT)
+ server.start()
+ try:
+ while True:
+ time.sleep(_ONE_DAY_IN_SECONDS)
+ except KeyboardInterrupt:
+ server.stop(0)
+
+
+if __name__ == '__main__':
+ serve(sys.argv[1])
diff --git a/clover/tools/jmeter/jmeter-master/process/grpc_process.sh b/clover/tools/jmeter/jmeter-master/process/grpc_process.sh
new file mode 100755
index 0000000..0f14d7c
--- /dev/null
+++ b/clover/tools/jmeter/jmeter-master/process/grpc_process.sh
@@ -0,0 +1,11 @@
+#!/bin/bash
+#
+# Copyright (c) Authors of Clover
+#
+# All rights reserved. This program and the accompanying materials
+# are made available under the terms of the Apache License, Version 2.0
+# which accompanies this distribution, and is available at
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+
+python grpc/jmeter_server.py test1
diff --git a/clover/tools/jmeter/jmeter-master/tests/jmx.template b/clover/tools/jmeter/jmeter-master/tests/jmx.template
new file mode 100644
index 0000000..1a6fa95
--- /dev/null
+++ b/clover/tools/jmeter/jmeter-master/tests/jmx.template
@@ -0,0 +1,135 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<jmeterTestPlan version="1.2" properties="4.0" jmeter="4.0 r1823414">
+ <hashTree>
+ <TestPlan guiclass="TestPlanGui" testclass="TestPlan" testname="Test Plan" enabled="true">
+ <stringProp name="TestPlan.comments"></stringProp>
+ <boolProp name="TestPlan.functional_mode">false</boolProp>
+ <boolProp name="TestPlan.tearDown_on_shutdown">true</boolProp>
+ <boolProp name="TestPlan.serialize_threadgroups">false</boolProp>
+ <elementProp name="TestPlan.user_defined_variables" elementType="Arguments" guiclass="ArgumentsPanel" testclass="Arguments" testname="User Defined Variables" enabled="true">
+ <collectionProp name="Arguments.arguments"/>
+ </elementProp>
+ <stringProp name="TestPlan.user_define_classpath"></stringProp>
+ </TestPlan>
+ <hashTree>
+ <ThreadGroup guiclass="ThreadGroupGui" testclass="ThreadGroup" testname="ThreadGroup" enabled="true">
+ <stringProp name="ThreadGroup.on_sample_error">continue</stringProp>
+ <elementProp name="ThreadGroup.main_controller" elementType="LoopController" guiclass="LoopControlPanel" testclass="LoopController" testname="ThreadGroup" enabled="true">
+ <boolProp name="LoopController.continue_forever">false</boolProp>
+ <intProp name="LoopController.loops">{{ loops }}</intProp>
+ </elementProp>
+ <stringProp name="ThreadGroup.num_threads">{{ num_threads }}</stringProp>
+ <stringProp name="ThreadGroup.ramp_time">{{ ramp_time }}</stringProp>
+ <longProp name="ThreadGroup.start_time">1385457190000</longProp>
+ <longProp name="ThreadGroup.end_time">1385457190000</longProp>
+ <boolProp name="ThreadGroup.scheduler">true</boolProp>
+ <stringProp name="ThreadGroup.duration">60</stringProp>
+ <stringProp name="ThreadGroup.delay"/>
+ <boolProp name="ThreadGroup.delayedStart">true</boolProp>
+ </ThreadGroup>
+ <hashTree>
+ {%- for u in url_list %}
+ <HTTPSampler guiclass="HttpTestSampleGui" testclass="HTTPSampler" testname="{{ url_names[loop.index0] }}" enabled="true">
+ <elementProp name="HTTPsampler.Arguments" elementType="Arguments" guiclass="HTTPArgumentsPanel" testclass="Arguments" testname="{{ url_names[loop.index0] }}" enabled="true">
+ <collectionProp name="Arguments.arguments"/>
+ </elementProp>
+ <stringProp name="HTTPSampler.domain">{{ u['domain'] }}</stringProp>
+ <stringProp name="HTTPSampler.port">{{ u['port'] }}</stringProp>
+ <stringProp name="HTTPSampler.connect_timeout"/>
+ <stringProp name="HTTPSampler.response_timeout"/>
+ <stringProp name="HTTPSampler.protocol">http</stringProp>
+ <stringProp name="HTTPSampler.contentEncoding"/>
+ <stringProp name="HTTPSampler.path">{{ u['path'] }}</stringProp>
+ <stringProp name="HTTPSampler.method">{{ url_methods[loop.index0] }}</stringProp>
+ <boolProp name="HTTPSampler.follow_redirects">true</boolProp>
+ <boolProp name="HTTPSampler.auto_redirects">false</boolProp>
+ <boolProp name="HTTPSampler.use_keepalive">true</boolProp>
+ <boolProp name="HTTPSampler.DO_MULTIPART_POST">false</boolProp>
+ <boolProp name="HTTPSampler.monitor">false</boolProp>
+ <stringProp name="HTTPSampler.embedded_url_re"/>
+ <stringProp name="HTTPSampler.implementation"/>
+ </HTTPSampler>
+ <hashTree/>
+ {%- endfor %}
+
+
+ </hashTree>
+ <ResultCollector guiclass="SummaryReport" testclass="ResultCollector" testname="Summary Report" enabled="true">
+ <boolProp name="ResultCollector.error_logging">false</boolProp>
+ <objProp>
+ <name>saveConfig</name>
+ <value class="SampleSaveConfiguration">
+ <time>true</time>
+ <latency>true</latency>
+ <timestamp>true</timestamp>
+ <success>true</success>
+ <label>true</label>
+ <code>true</code>
+ <message>true</message>
+ <threadName>true</threadName>
+ <dataType>true</dataType>
+ <encoding>false</encoding>
+ <assertions>true</assertions>
+ <subresults>true</subresults>
+ <responseData>false</responseData>
+ <samplerData>false</samplerData>
+ <xml>false</xml>
+ <fieldNames>true</fieldNames>
+ <responseHeaders>false</responseHeaders>
+ <requestHeaders>false</requestHeaders>
+ <responseDataOnError>false</responseDataOnError>
+ <saveAssertionResultsFailureMessage>true</saveAssertionResultsFailureMessage>
+ <assertionsResultsToSave>0</assertionsResultsToSave>
+ <bytes>true</bytes>
+ <sentBytes>true</sentBytes>
+ <threadCounts>true</threadCounts>
+ <idleTime>true</idleTime>
+ <connectTime>true</connectTime>
+ </value>
+ </objProp>
+ <stringProp name="filename">/jmeter/bin/results2</stringProp>
+ </ResultCollector>
+ <hashTree/>
+
+
+ <ResultCollector guiclass="StatVisualizer" testclass="ResultCollector" testname="Aggregate Report" enabled="true">
+ <boolProp name="ResultCollector.error_logging">false</boolProp>
+ <objProp>
+ <name>saveConfig</name>
+ <value class="SampleSaveConfiguration">
+ <time>true</time>
+ <latency>true</latency>
+ <timestamp>true</timestamp>
+ <success>true</success>
+ <label>true</label>
+ <code>true</code>
+ <message>true</message>
+ <threadName>true</threadName>
+ <dataType>true</dataType>
+ <encoding>false</encoding>
+ <assertions>true</assertions>
+ <subresults>true</subresults>
+ <responseData>false</responseData>
+ <samplerData>false</samplerData>
+ <xml>false</xml>
+ <fieldNames>true</fieldNames>
+ <responseHeaders>false</responseHeaders>
+ <requestHeaders>false</requestHeaders>
+ <responseDataOnError>false</responseDataOnError>
+ <saveAssertionResultsFailureMessage>true</saveAssertionResultsFailureMessage>
+ <assertionsResultsToSave>0</assertionsResultsToSave>
+ <bytes>true</bytes>
+ <sentBytes>true</sentBytes>
+ <threadCounts>true</threadCounts>
+ <idleTime>true</idleTime>
+ <connectTime>true</connectTime>
+ </value>
+ </objProp>
+ <stringProp name="filename">/jmeter/bin/results_aggregate</stringProp>
+ </ResultCollector>
+ <hashTree/>
+
+
+ </hashTree>
+ </hashTree>
+</jmeterTestPlan>
diff --git a/clover/tools/jmeter/jmeter-slave/Dockerfile b/clover/tools/jmeter/jmeter-slave/Dockerfile
new file mode 100644
index 0000000..b5ccbcd
--- /dev/null
+++ b/clover/tools/jmeter/jmeter-slave/Dockerfile
@@ -0,0 +1,27 @@
+# Copyright (c) Authors of Clover
+#
+# All rights reserved. This program and the accompanying materials
+# are made available under the terms of the Apache License, Version 2.0
+# which accompanies this distribution, and is available at
+# http://www.apache.org/licenses/LICENSE-2.0
+
+FROM java:8
+
+RUN wget http://apache.mirrors.hoobly.com//jmeter/binaries/apache-jmeter-4.0.tgz
+RUN tar -xvzf apache-jmeter-4.0.tgz
+RUN rm apache-jmeter-4.0.tgz
+RUN mv apache-jmeter-4.0 /jmeter
+ENV JMETER_HOME /jmeter
+ENV PATH $JMETER_HOME/bin:$PATH
+RUN mkdir /share
+COPY rmi_keystore.jks $JMETER_HOME/bin
+
+WORKDIR $JMETER_HOME
+# Ports to be exposed from the container for JMeter Master
+RUN mkdir scripts
+
+EXPOSE 1099
+
+WORKDIR /jmeter/bin
+
+CMD ./jmeter-server
diff --git a/clover/tools/jmeter/rmi_keystore.jks b/clover/tools/jmeter/rmi_keystore.jks
new file mode 100644
index 0000000..f503361
--- /dev/null
+++ b/clover/tools/jmeter/rmi_keystore.jks
Binary files differ
diff --git a/clover/tools/jmeter/yaml/manifest.template b/clover/tools/jmeter/yaml/manifest.template
new file mode 100644
index 0000000..01a4595
--- /dev/null
+++ b/clover/tools/jmeter/yaml/manifest.template
@@ -0,0 +1,45 @@
+---
+apiVersion: extensions/v1beta1
+kind: Deployment
+metadata:
+ name: {{ deploy_name }}
+ labels:
+ app: {{ deploy_name }}
+spec:
+{%- if replica_count %}
+ replicas: 3{% endif %}
+ template:
+ metadata:
+ labels:
+ app: {{ deploy_name }}
+ spec:
+ containers:
+ - name: {{ deploy_name }}
+ image: {{ image_path }}/{{ image_name }}:{{ image_tag }}
+ ports:
+{%- if grpc_port %}
+ - containerPort: {{ grpc_port }}{% endif %}
+ - containerPort: {{ rmi_port }}
+ - containerPort: {{ http_port }}
+ - containerPort: {{ ssl_port }}
+---
+apiVersion: v1
+kind: Service
+metadata:
+ name: {{ deploy_name }}
+ labels:
+ app: {{ deploy_name }}
+spec:
+ ports:
+{%- if grpc_port %}
+ - port: {{ grpc_port }}
+ name: grpc{% endif %}
+ - port: {{ rmi_port }}
+ name: rmi
+ - port: {{ http_port }}
+ name: http
+ - port: {{ ssl_port }}
+ name: https
+ selector:
+ app: {{ deploy_name }}
+---
diff --git a/clover/tools/jmeter/yaml/render_master.py b/clover/tools/jmeter/yaml/render_master.py
new file mode 100644
index 0000000..884ee81
--- /dev/null
+++ b/clover/tools/jmeter/yaml/render_master.py
@@ -0,0 +1,67 @@
+# Copyright (c) Authors of Clover
+#
+# All rights reserved. This program and the accompanying materials
+# are made available under the terms of the Apache License, Version 2.0
+# which accompanies this distribution, and is available at
+# http://www.apache.org/licenses/LICENSE-2.0
+
+import argparse
+
+from jinja2 import Template
+
+
+def render_yaml(args):
+ template_file = 'manifest.template'
+ out_file = args['deploy_name'] + '.yaml'
+
+ try:
+ with open(template_file) as f:
+ tmpl = Template(f.read())
+ output = tmpl.render(
+ image_path=args['image_path'],
+ image_name=args['image_name'],
+ image_tag=args['image_tag'],
+ deploy_name=args['deploy_name'],
+ grpc_port=args['grpc_port'],
+ ssl_port=args['ssl_port'],
+ rmi_port=args['rmi_port'],
+ http_port=args['http_port']
+ )
+ with open(out_file, "wb") as fh:
+ fh.write(output)
+ return "Generated manifest for {}".format(args['deploy_name'])
+ except Exception as e:
+ print(e)
+ return "Unable to generate manifest for {}".format(
+ args['deploy_name'])
+
+
+if __name__ == '__main__':
+ parser = argparse.ArgumentParser()
+ parser.add_argument(
+ '--image_name', default='clover-jmeter-master',
+ help='The image name to use')
+ parser.add_argument(
+ '--image_path', default='localhost:5000',
+ help='The path to the image to use')
+ parser.add_argument(
+ '--image_tag', default='latest',
+ help='The image tag to use')
+ parser.add_argument(
+ '--deploy_name', default='clover-jmeter-master',
+ help='The k8s deploy name to use')
+ parser.add_argument(
+ '--rmi_port', default='1099',
+ help='The master-slave remote method invocation port')
+ parser.add_argument(
+ '--http_port', default='80',
+ help='HTTP data-plane traffic')
+ parser.add_argument(
+ '--grpc_port', default='50054',
+ help='The GRPC server port for management')
+ parser.add_argument(
+ '--ssl_port', default='443',
+ help='HTTPS data-plane traffic')
+
+ args = parser.parse_args()
+ print(render_yaml(vars(args)))
diff --git a/clover/tools/jmeter/yaml/render_slave.py b/clover/tools/jmeter/yaml/render_slave.py
new file mode 100644
index 0000000..cd9fd91
--- /dev/null
+++ b/clover/tools/jmeter/yaml/render_slave.py
@@ -0,0 +1,67 @@
+# Copyright (c) Authors of Clover
+#
+# All rights reserved. This program and the accompanying materials
+# are made available under the terms of the Apache License, Version 2.0
+# which accompanies this distribution, and is available at
+# http://www.apache.org/licenses/LICENSE-2.0
+
+import argparse
+
+from jinja2 import Template
+
+
+def render_yaml(args):
+ template_file = 'manifest.template'
+ out_file = args['deploy_name'] + '.yaml'
+
+ try:
+ with open(template_file) as f:
+ tmpl = Template(f.read())
+ output = tmpl.render(
+ image_path=args['image_path'],
+ image_name=args['image_name'],
+ image_tag=args['image_tag'],
+ deploy_name=args['deploy_name'],
+ replica_count=args['replica_count'],
+ ssl_port=args['ssl_port'],
+ rmi_port=args['rmi_port'],
+ http_port=args['http_port']
+ )
+ with open(out_file, "wb") as fh:
+ fh.write(output)
+ return "Generated manifest for {}".format(args['deploy_name'])
+ except Exception as e:
+ print(e)
+ return "Unable to generate manifest for {}".format(
+ args['deploy_name'])
+
+
+if __name__ == '__main__':
+ parser = argparse.ArgumentParser()
+ parser.add_argument(
+ '--image_name', default='clover-jmeter-slave',
+ help='The image name to use')
+ parser.add_argument(
+ '--image_path', default='localhost:5000',
+ help='The path to the image to use')
+ parser.add_argument(
+ '--image_tag', default='latest',
+ help='The image tag to use')
+ parser.add_argument(
+ '--deploy_name', default='clover-jmeter-slave',
+ help='The k8s deploy name to use')
+ parser.add_argument(
+ '--rmi_port', default='1099',
+ help='The master-slave remote method invocation port')
+ parser.add_argument(
+ '--http_port', default='80',
+ help='HTTP data-plane traffic')
+ parser.add_argument(
+ '--replica_count', default='3',
+ help='Number of replicas in slave deployment')
+ parser.add_argument(
+ '--ssl_port', default='443',
+ help='HTTPS data-plane traffic')
+
+ args = parser.parse_args()
+ print(render_yaml(vars(args)))