Controller installation
This page contains information on installing and configuring Step Controller.
Prerequisites
Step requires at least Java 11 installed on your machine to run. Depending on your platform, make sure to install at least the Java JDK 11 on the machine(s) running Step component(s).
Binaries download
The latest version of the Community Edition of the Step controller can be downloaded from our Github repository at : Step.
The latest version of the Enterprise Edition of the Step controller can be downloaded from our FTP by enterprise customers at : Step Enterprise (credentials are provided upon requests)
In both cases, extract the Step Controller archive using any unarchiver tool that support the zip format.
Folder Structure
Below the description of the Controller structure folder :
controller/
├── bin : contains startup scripts
├── conf : contains configurations files
├── data : contains demo scripts and testing data
├── ext : default location for external software binaries
├── lib : contains dependencies libraries
└── log : default location for the log files
Configuration
Configuration files can be found under the controller/conf folder and contains the following :
conf/
├── QuotaManagerConfig.xml
└── step.properties
Main properties
Main configuration file that needs to be tuned is step.properties, other ones can be left untouched.
The main parameters to be updated in order to start the Controller are listed below :
- port=<port_to_access_controller_gui>
- grid.port=<port_for_agents_to_access_the_controller>
- db.host=<mongo_hostname_or_ip>
- db.port=<mongo_port>
- db.username=<step_database_username> (if any)
- db.password=<step_database_password> (if any)
For example :
- port=8080 -> Controller GUI will be accessible on port 8080
- grid.port=8081 -> Agents will connect to the Controller on port 8081
- db.host=127.0.0.1 -> Controller will try to access to MongoDB running on localhost
- db.port=27017 -> Controller will try to access to MongoDB on port 27017
For the Step Controller Enterprise version, the step.properties file contains all the available properties and are directly documented into the file itself.
SSL Setup (optional)
Per default the controller GUI is accessible via HTTP and SSL is disabled. It is highly recommended to secure your controller instance by enabling SSL.
Before enabling SSL you will need a valid SSL certificate for your controller domain. You can either use a self-signed certificate or obtain it from a certificate authority (CA).
In both cases you’ll get following files:
- the private key file (.key)
- the certificate file (.cert)
The controller requires the certificate in a Java KeyStore in JKS format. To generate the JKS KeyStore based on your .key and .cert files, follow the steps described here
As soon as you have your certificate in JKS format as a .jks file you can enable SSL as follow:
Put the keystore file (mydomain.jks for example) in conf folder of the controller and add the following lines to the step.properties file :
#-----------------------------------------------------
# SSL configuration
#-----------------------------------------------------
ui.ssl.enabled=true
ui.ssl.keystore.path=../conf/mydomain.jks
ui.ssl.keystore.password=<PASSWORD_DEFINED_DURING_P12_KEYSTORE_CREATION>
ui.ssl.keymanager.password=<PASSWORD_DEFINED_DURING_P12_KEYSTORE_CREATION>
#-----------------------------------------------------
Ldap setup (optional)
You can use LDAP to authenticate to Step by by un-commenting the following properties is step.properties:
# Authenticator configuration - example for LDAP
ui.authenticator=step.core.access.LdapAuthenticator
# url of your LDAP server
ui.authenticator.ldap.url=<url>
# root named context for searching for users
ui.authenticator.ldap.base=dc=<>,dc=<>
# search filter - {user} will be replaced with the username
ui.authenticator.ldap.filter=(cn={user})
# user used for connecting to the LDAP server
ui.authenticator.ldap.techuser=cn=<>,dc=<>,dc=<>
ui.authenticator.ldap.techpwd=<PWD>
# Use following flag to manage users from LDAP (authenticated user will be created automatically in Step)
#ui.authenticator.as.user.manager=true
# Define which default role is used to create users
ui.authenticator.user.creation.default.role=guest
Open id connect setup (optional)
You can integrate with your OpenId Connect Identify Provider by adding following configuration to your step.properties. Depending on the configuration used, you may delegate the user and role management to the Identity Provider
Note: make sure the below properties are not set elsewhere
# Authenticator configuration - example for OIDC
ui.authenticator=step.core.access.OidcAuthenticator
# Use following flag to manage users from OIDC (authenticated user will be created automatically in Step)
ui.authenticator.as.user.manager=true
# Define which default role is used to create users (when ui.authenticator.as.role.manager=false)
ui.authenticator.user.creation.default.role=guest
# Define the json path to extract the username for the JWT token (default preferred_username)
# authenticator.jwt.oidc.user-claim-name=preferred_username
# Use following flag to manage roles from OIDC (extracted role will be assigned to the user in Step)
ui.authenticator.as.role.manager=true
# List of json path to extract the role and map them to Step's roles
authenticator.jwt.oidc.roles.jsonpath.admin=$.resource_access.step-local.roles[?(@ =~ /admin/)]
authenticator.jwt.oidc.roles.jsonpath.developer=$.resource_access.step-local.roles[?(@ =~ /developer/)]
authenticator.jwt.oidc.roles.jsonpath.tester=$.resource_access.step-local.roles[?(@ =~ /tester/)]
authenticator.jwt.oidc.roles.jsonpath.guest=$.resource_access.step-local.roles[?(@ =~ /guest/)]
# Ordering (priority of roles) is required in case the user was assigned multiple Step roles in IDM.
# From left to right: lowest to the highest priority (roles not defined in this list have the lower priority)
authenticator.jwt.oidc.roles.order=guest,tester,developer,admin
# Open Id Connect configurations
authenticator.oidc.client_id=<your-client-id>
authenticator.oidc.client_secret=<your-client-secret>
# Define your Oidc issuer path, the well-known endpoint must be available at <your-issuer-path>/.well-known/openid-configuration
authenticator.oidc.issuer=<your-issuer-path>
authenticator.oidc.scope=openid email profile
# turn off if you don't want or cannot validate the audience during the access token validation (true of not set)
authenticator.jwt.oidc.audience.check=true
authenticator.jwt.oidc.audience=<audience-name>
License (Enterprise version only)
For the Step Controller Enterprise version, you will need to put your purchased Step license file under the Controller “bin” directory prior to starting it.
Configuration placeholders (advanced)
Placeholders can be used in step.properties to define dynamic values that have to be set at startup outside the configuration file.
For instance, you might want to set the port of the GUI at startup. You could achieve this using a placeholder like this:
- port=${myPort}
and set the variable myPort in the startup script startController.bat(sh|command):
"%JAVA_PATH%java.exe" %JAVA_OPTS% -cp "..\lib\*;" step.controller.ControllerServer -config=../conf/step.properties -myPort=8080
Startup
Startup scripts can be found under controller/bin and contains the following :
bin/
├── logback.xml
├── startController.bat
├── startController.command
├── startController.sh
├── startMongo.bat
├── startMongo.command
└── startMongo.sh
There are convenient scripts in order to start MongoDB too, you can use them once you have MongoDB installed and set in your path. Warning : before trying to start the Controller, make sure Java binaries are set in your system path !
Depending on your platform, they are various ways to start the Controller :
- Windows
execute startController.bat - Linux
make startController.sh executable and execute it - Mac OS
make startController.command executable and execute it.
The web application should now be available on your host on the port you defined in the configuration file (for example at http://localhost:8080) You will be then prompted for login information, default is admin // init :
You can now see the Controller interface, by default opened on the “Plan” tab :
Log verbosity
You can easily change the logging verbosity by tweaking the “root” log level present in the file logback.xml. Below an example with the root log level verbosity set to “error” :
<!--
(C) Copyright 2016 Jerome Comte and Dorian Cransac
This file is part of STEP
STEP is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
STEP is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with STEP. If not, see <http://www.gnu.org/licenses/>.
-->
<configuration scan="true">
<appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>../log/controller.log</file>
<encoder>
<pattern>%date %level [%thread] %logger{10} [%file:%line] %msg%n</pattern>
</encoder>
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<fileNamePattern>../log/controller.%d{yyyy-MM-dd}.log</fileNamePattern>
<maxHistory>30</maxHistory>
</rollingPolicy>
</appender>
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>%msg%n</pattern>
</encoder>
</appender>
<logger name="org.lightcouch" level="error" />
<!-- <logger name="io.djigger...." level="debug" /> -->
<root level="error">
<appender-ref ref="STDOUT" />
<appender-ref ref="FILE" />
</root>
</configuration>
Audit log
Security-relevant events such as user login/logout, session invalidation, and password changes are logged
using the special class AuditLogger
.
The enterprise version of Step already ships a tailored log configuration which logs these events to the file audit-logger.log
in the log/
directory.
Installation as a Service (optional)
Linux (systemd)
To install the controller as a systemd service, follow the steps below:
As the root user, create the file /etc/systemd/system/step-controller.service
with the following content:
[Unit]
Description=Step controller
[Service]
User=step
WorkingDirectory=/var/opt/step/bin
ExecStart=/usr/bin/java \
-Dlogback.configurationFile=./logback.xml \
-Dhttp.keepAlive=true \
-Dhttp.maxConnections=100 \
-cp ../lib/*: \
step.controller.ControllerServer \
-config=../conf/step.properties
SuccessExitStatus=143
[Install]
WantedBy=multi-user.target
Make sure to adjust the User and WorkingDirectory settings to your installation!
Ensure that the file has correct ownership and permissions:
chown root:root /etc/systemd/system/step-controller.service
chmod 644 /etc/systemd/system/step-controller.service
Finally, tell systemd to apply the new settings and enable the service:
systemctl daemon-reload
systemctl enable step-controller
systemctl restart step-controller
Microsoft Windows
In order to install the controller as a Windows service, follow the steps below:
- download nssm at https://nssm.cc/download
- open a new command prompt as Administrator and navigate to the nssm executable location
- execute the following command :
nssm install
- nssm gui will open, you can now specify the “startController.bat” location and the service name, then click on “Install service” :
- You should then be prompted that the service installation has been successful :
- you can double-check into Windows service list that the service has been properly installed and then you can start it :
Installation checks
Running process
Depending on your platform, they are various ways to check if the Controller is running :
- Windows: open the Task Manager and look for the Java processes
- Linux: execute below command and check that a PID is returned :
ps -efl | grep ControllerServer.
- Mac OS: open the Activity Monitor and look for the Java processes
Log file
The Controller log file will be created on first startup under the log folder. (You can change the log file location by editing the bin/logback.xml file). A successful startup should display the following entry into the log file :
2017-09-26 02:02:11,371 INFO [main] o.e.j.u.log [Log.java:186] Logging initialized @1068ms
2017-09-26 02:02:12,046 INFO [main] o.r.Reflections [Reflections.java:229] Reflections took 560 ms to scan 13 urls, producing 124 keys and 413 values
2017-09-26 02:02:12,241 INFO [main] o.m.d.cluster [SLF4JLogger.java:71] Cluster created with settings {hosts=[mongo:27017], mode=SINGLE, requiredClusterType=UNKNOWN, serverSelectionTimeout='30000 ms', maxWaitQueueSize=500}
2017-09-26 02:02:12,278 INFO [main] o.m.d.cluster [SLF4JLogger.java:71] Cluster created with settings {hosts=[mongo:27017], mode=SINGLE, requiredClusterType=UNKNOWN, serverSelectionTimeout='30000 ms', maxWaitQueueSize=500}
2017-09-26 02:02:12,464 INFO [cluster-ClusterId{value='59c9b524133ae60008eec74f', description='null'}-mongo:27017] o.m.d.connection [SLF4JLogger.java:71] Opened connection [connectionId{localValue:2, serverValue:2}] to mongo:27017
2017-09-26 02:02:12,470 INFO [cluster-ClusterId{value='59c9b524133ae60008eec74f', description='null'}-mongo:27017] o.m.d.cluster [SLF4JLogger.java:71] Monitor thread successfully connected to server with description ServerDescription{address=mongo:27017, type=STANDALONE, state=CONNECTED, ok=true, version=ServerVersion{versionList=[3, 4, 9]}, minWireVersion=0, maxWireVersion=5, maxDocumentSize=16777216, roundTripTimeNanos=3533336}
2017-09-26 02:02:12,491 INFO [cluster-ClusterId{value='59c9b524133ae60008eec74e', description='null'}-mongo:27017] o.m.d.connection [SLF4JLogger.java:71] Opened connection [connectionId{localValue:1, serverValue:1}] to mongo:27017
2017-09-26 02:02:12,498 INFO [cluster-ClusterId{value='59c9b524133ae60008eec74e', description='null'}-mongo:27017] o.m.d.cluster [SLF4JLogger.java:71] Monitor thread successfully connected to server with description ServerDescription{address=mongo:27017, type=STANDALONE, state=CONNECTED, ok=true, version=ServerVersion{versionList=[3, 4, 9]}, minWireVersion=0, maxWireVersion=5, maxDocumentSize=16777216, roundTripTimeNanos=6662765}
2017-09-26 02:02:12,900 INFO [main] o.m.d.connection [SLF4JLogger.java:71] Opened connection [connectionId{localValue:3, serverValue:3}] to mongo:27017
2017-09-26 02:02:14,453 INFO [main] s.i.InitializationPlugin [InitializationPlugin.java:110] Searching for artefacts of type 'CallFunction' to be migrated...
2017-09-26 02:02:14,456 INFO [main] s.i.InitializationPlugin [InitializationPlugin.java:139] Migrated 0 artefacts of type 'CallFunction'
2017-09-26 02:02:14,456 INFO [main] s.i.InitializationPlugin [InitializationPlugin.java:143] Searching for artefacts of type 'FunctionGroup' to be migrated...
2017-09-26 02:02:14,458 INFO [main] s.i.InitializationPlugin [InitializationPlugin.java:166] Migrated 0 artefacts of type 'FunctionGroup'
2017-09-26 02:02:14,458 INFO [main] s.i.InitializationPlugin [InitializationPlugin.java:143] Searching for artefacts of type 'CallFunction' to be migrated...
2017-09-26 02:02:14,459 INFO [main] s.i.InitializationPlugin [InitializationPlugin.java:166] Migrated 0 artefacts of type 'CallFunction'
2017-09-26 02:02:16,210 INFO [main] o.r.c.MeasurementAccessor [MeasurementAccessor.java:74] Initializing db with address=mongo:27017, credentials=[]
2017-09-26 02:02:16,210 INFO [main] o.m.d.cluster [SLF4JLogger.java:71] Cluster created with settings {hosts=[mongo:27017], mode=SINGLE, requiredClusterType=UNKNOWN, serverSelectionTimeout='30000 ms', maxWaitQueueSize=500}
2017-09-26 02:02:16,212 INFO [main] o.m.d.cluster [SLF4JLogger.java:71] Cluster description not yet available. Waiting for 30000 ms before timing out
2017-09-26 02:02:16,218 INFO [cluster-ClusterId{value='59c9b528133ae60008eec75c', description='null'}-mongo:27017] o.m.d.connection [SLF4JLogger.java:71] Opened connection [connectionId{localValue:4, serverValue:6}] to mongo:27017
2017-09-26 02:02:16,219 INFO [cluster-ClusterId{value='59c9b528133ae60008eec75c', description='null'}-mongo:27017] o.m.d.cluster [SLF4JLogger.java:71] Monitor thread successfully connected to server with description ServerDescription{address=mongo:27017, type=STANDALONE, state=CONNECTED, ok=true, version=ServerVersion{versionList=[3, 4, 9]}, minWireVersion=0, maxWireVersion=5, maxDocumentSize=16777216, roundTripTimeNanos=559924}
2017-09-26 02:02:16,639 INFO [main] o.r.Reflections [Reflections.java:229] Reflections took 270 ms to scan 13 urls, producing 124 keys and 413 values
2017-09-26 02:02:16,861 INFO [main] o.e.j.s.Server [Server.java:327] jetty-9.2.17.v20160517
2017-09-26 02:02:18,048 INFO [main] o.e.j.s.h.ContextHandler [ContextHandler.java:744] Started o.e.j.s.ServletContextHandler@acd3460{/,null,AVAILABLE}
2017-09-26 02:02:18,068 INFO [main] o.e.j.s.ServerConnector [AbstractConnector.java:266] Started ServerConnector@5bba9949{HTTP/1.1}{0.0.0.0:8081}
2017-09-26 02:02:18,069 INFO [main] o.e.j.s.Server [Server.java:379] Started @7768ms
2017-09-26 02:02:18,208 WARN [main] o.e.j.s.h.ContextHandler [ContextHandler.java:1344] o.e.j.s.h.ContextHandler@206bd7a0{/,null,null} contextPath ends with /
2017-09-26 02:02:18,214 WARN [main] o.e.j.s.h.ContextHandler [ContextHandler.java:1344] o.e.j.s.h.ContextHandler@5a31abe9{/,null,null} contextPath ends with /
2017-09-26 02:02:18,216 WARN [main] o.e.j.s.h.ContextHandler [ContextHandler.java:1344] o.e.j.s.h.ContextHandler@2dacda9a{/,null,null} contextPath ends with /
2017-09-26 02:02:18,275 INFO [main] o.q.i.StdSchedulerFactory [StdSchedulerFactory.java:1184] Using default implementation for ThreadExecutor
2017-09-26 02:02:18,299 INFO [main] o.q.c.SchedulerSignalerImpl [SchedulerSignalerImpl.java:61] Initialized Scheduler Signaller of type: class org.quartz.core.SchedulerSignalerImpl
2017-09-26 02:02:18,302 INFO [main] o.q.c.QuartzScheduler [QuartzScheduler.java:240] Quartz Scheduler v.2.2.1 created.
2017-09-26 02:02:18,304 INFO [main] o.q.s.RAMJobStore [RAMJobStore.java:155] RAMJobStore initialized.
2017-09-26 02:02:18,307 INFO [main] o.q.c.QuartzScheduler [QuartzScheduler.java:305] Scheduler meta-data: Quartz Scheduler (v2.2.1) 'QuartzScheduler' with instanceId 'NON_CLUSTERED'
Scheduler class: 'org.quartz.core.QuartzScheduler' - running locally.
NOT STARTED.
Currently in standby mode.
Number of jobs executed: 0
Using thread pool 'org.quartz.simpl.SimpleThreadPool' - with 10 threads.
Using job-store 'org.quartz.simpl.RAMJobStore' - which does not support persistence. and is not clustered.
2017-09-26 02:02:18,308 INFO [main] o.q.i.StdSchedulerFactory [StdSchedulerFactory.java:1339] Quartz scheduler 'QuartzScheduler' initialized from an externally provided properties instance.
2017-09-26 02:02:18,308 INFO [main] o.q.i.StdSchedulerFactory [StdSchedulerFactory.java:1343] Quartz scheduler version: 2.2.1
2017-09-26 02:02:18,312 INFO [main] o.q.c.QuartzScheduler [QuartzScheduler.java:2311] JobFactory set to: step.core.scheduler.ExecutionJobFactory@153409b8
2017-09-26 02:02:18,313 INFO [main] o.q.c.QuartzScheduler [QuartzScheduler.java:575] Scheduler QuartzScheduler_$_NON_CLUSTERED started.
2017-09-26 02:02:18,341 INFO [main] o.e.j.s.Server [Server.java:327] jetty-9.2.17.v20160517
2017-09-26 02:02:19,100 INFO [main] o.e.j.w.StandardDescriptorProcessor [StandardDescriptorProcessor.java:297] NO JSP Support for /rtm, did not find org.eclipse.jetty.jsp.JettyJspServlet
2017-09-26 02:02:19,289 INFO [main] o.e.j.s.h.ContextHandler [ContextHandler.java:744] Started o.e.j.w.WebAppContext@9825465{/rtm,file:/tmp/jetty-0.0.0.0-8080-rtm-2.0.3.war-_rtm-any-4312820959754652971.dir/webapp/,AVAILABLE}{../ext/rtm-2.0.3.war}
2017-09-26 02:02:19,290 INFO [main] o.e.j.s.h.ContextHandler [ContextHandler.java:744] Started o.e.j.s.h.ContextHandler@206bd7a0{/scripteditor,null,AVAILABLE}
2017-09-26 02:02:19,290 INFO [main] o.e.j.s.h.ContextHandler [ContextHandler.java:744] Started o.e.j.s.h.ContextHandler@5a31abe9{/seleniumplugin,null,AVAILABLE}
2017-09-26 02:02:19,291 INFO [main] o.e.j.s.h.ContextHandler [ContextHandler.java:744] Started o.e.j.s.h.ContextHandler@2dacda9a{/jmeterplugin,null,AVAILABLE}
2017-09-26 02:02:19,645 INFO [main] o.e.j.s.h.ContextHandler [ContextHandler.java:744] Started o.e.j.s.ServletContextHandler@36cf6377{/rest,null,AVAILABLE}
2017-09-26 02:02:19,646 INFO [main] o.e.j.s.h.ContextHandler [ContextHandler.java:744] Started o.e.j.s.h.ContextHandler@2befb16f{/,null,AVAILABLE}
2017-09-26 02:02:19,647 INFO [main] o.e.j.s.h.ContextHandler [ContextHandler.java:744] Started o.e.j.s.ServletContextHandler@3151277f{/files,null,AVAILABLE}
2017-09-26 02:02:19,647 INFO [main] o.e.j.s.ServerConnector [AbstractConnector.java:266] Started ServerConnector@2d117280{HTTP/1.1}{0.0.0.0:8080} 2017-09-26 02:02:19,648 INFO [main] o.e.j.s.Server [Server.java:379] Started @9347ms