Skip to content

Commit b4c25e4

Browse files
Merge pull request #664 from atlassian/DCA-1261-create-prepare-data-bamboo
Bamboo prepare_data and related API client
2 parents 20d4817 + d0013c0 commit b4c25e4

File tree

5 files changed

+254
-1
lines changed

5 files changed

+254
-1
lines changed

app/bamboo.yml

Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
---
2+
settings:
3+
artifacts-dir: results/bamboo/%Y-%m-%d_%H-%M-%S
4+
aggregator: consolidator
5+
verbose: false
6+
env:
7+
application_hostname: test-bamboo.atlassian.com # Bamboo DC hostname without protocol and port e.g. test-bamboo.atlassian.com or localhost
8+
application_protocol: http # http or https
9+
application_port: 8085 # 80, 443, 8080, etc
10+
secure: True # Set False to allow insecure connections, e.g. when using self-signed SSL certificate
11+
application_postfix: # e.g. /bamboo in case of url like http://localhost/bamboo
12+
admin_login: admin
13+
admin_password: admin
14+
load_executor: jmeter
15+
concurrency: 1000 # number of Bamboo users for Selenium actions
16+
test_duration: 45m
17+
18+
# 1 node scenario parameters
19+
ramp-up: 20s # time to spin all concurrent threads
20+
total_actions_per_hour: 180000 # number of total JMeter actions per hour
21+
22+
# 2 nodes scenario parameters
23+
# ramp-up: 10s # time to spin all concurrent threads
24+
# total_actions_per_hour: 360000 # number of total JMeter actions per hour
25+
26+
# 4 nodes scenario parameters
27+
# ramp-up: 5s # time to spin all concurrent threads
28+
# total_actions_per_hour: 720000 # number of total JMeter actions per hour
29+
30+
JMETER_VERSION: 5.2.1
31+
LANGUAGE: en_US.utf8
32+
allow_analytics: No # Allow sending basic run analytics to Atlassian. These analytics help us to understand how the tool is being used and help us to continue to invest in this tooling. For more details please see our README.
33+
services:
34+
- module: shellexec
35+
prepare:
36+
- python util/pre_run/environment_checker.py
37+
- python util/data_preparation/bamboo_prepare_data.py
38+
# shutdown:
39+
# - python util/post_run/jmeter_post_check.py
40+
# - python util/jtl_convertor/jtls-to-csv.py kpi.jtl
41+
# post-process:
42+
# - python util/analytics/analytics.py bamboo
43+
# - python util/post_run/cleanup_results_dir.py
44+
execution:
45+
- scenario: ${load_executor}
46+
executor: ${load_executor}
47+
concurrency: ${concurrency}
48+
hold-for: ${test_duration}
49+
ramp-up: ${ramp-up}
50+
scenarios:
51+
jmeter:
52+
script: jmeter/bamboo.jmx
53+
properties:
54+
application_hostname: ${application_hostname}
55+
application_protocol: ${application_protocol}
56+
application_port: ${application_port}
57+
application_postfix: ${application_postfix}
58+
# Workload model
59+
total_actions_per_hr: ${total_actions_per_hour}
60+
modules:
61+
consolidator:
62+
rtimes-len: 0 # CONFSRVDEV-7631 reduce sampling
63+
percentiles: [] # CONFSRVDEV-7631 disable all percentiles due to Taurus's excessive memory usage
64+
jmeter:
65+
version: ${JMETER_VERSION}
66+
detect-plugins: true
67+
memory-xmx: 8G # allow JMeter to use up to 8G of memory
68+
plugins:
69+
- bzm-parallel=0.4
70+
- bzm-random-csv=0.6
71+
- jpgc-casutg=2.5
72+
- jpgc-dummy=0.2
73+
- jpgc-ffw=2.0
74+
- jpgc-fifo=0.2
75+
- jpgc-functions=2.1
76+
- jpgc-json=2.6
77+
- jpgc-perfmon=2.1
78+
- jpgc-prmctl=0.4
79+
- jpgc-tst=2.4
80+
- jpgc-wsc=0.3
81+
- tilln-sshmon=1.0
82+
- jpgc-synthesis=2.2
83+
system-properties:
84+
server.rmi.ssl.disable: true
85+
java.rmi.server.hostname: localhost
86+
httpsampler.ignore_failed_embedded_resources: "true"
87+
reporting:
88+
- data-source: sample-labels
89+
module: junit-xml

app/util/api/bamboo_clients.py

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
from util.api.abstract_clients import RestClient
2+
3+
BATCH_SIZE_SEARCH = 500
4+
5+
6+
class BambooClient(RestClient):
7+
8+
def get_build_plans(self, start=0, max_result=100):
9+
loop_count = max_result // BATCH_SIZE_SEARCH + 1
10+
content = list()
11+
last_loop_remainder = max_result % BATCH_SIZE_SEARCH
12+
max_result = BATCH_SIZE_SEARCH if max_result > BATCH_SIZE_SEARCH else max_result
13+
14+
while loop_count > 0:
15+
if not max_result:
16+
break
17+
api_url = (
18+
self.host + f'/rest/api/latest/search/plans?start-index={start}'
19+
f'&max-result={max_result}'
20+
)
21+
request = self.get(api_url, "Could not retrieve build plans")
22+
if request.json()['start-index'] != start:
23+
break
24+
content.extend(request.json()['searchResults'])
25+
26+
loop_count -= 1
27+
if loop_count == 1:
28+
max_result = last_loop_remainder
29+
30+
start += len(request.json()['searchResults'])
31+
32+
return content
33+
34+
def get_users(self, limit):
35+
"""
36+
Retrieve a page of users. The authenticated user must have restricted
37+
administrative permission or higher to use this resource.
38+
:param start: The starting index of the returned users. Base index: 0.
39+
:param limit: The maximum number of users to return per page. Default: 25.
40+
"""
41+
request = self.get(f'{self.host}/rest/api/latest/admin/users?limit={limit}',
42+
error_msg="Can not retrieve users")
43+
content = request.json()
44+
return content['results']
45+
46+
def create_user(self, name, password):
47+
"""
48+
Create a new user. The authenticated user must have restricted administrative
49+
permission or higher to use this resource.
50+
:param name: username to create.
51+
:param fullName: full user name.
52+
:email: email address.
53+
:password: password.
54+
:passwordConfirm: confirm password.
55+
"""
56+
api_url = f'{self.host}/rest/api/latest/admin/users'
57+
payload = {"name": name,
58+
"fullName": name,
59+
"email": f'{name}@example.com',
60+
"password": password,
61+
"passwordConfirm": password}
62+
self.post(api_url, body=payload, error_msg="Could not create user")
63+
return {'name': name}

app/util/conf.py

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import yaml
22

3-
from util.project_paths import JIRA_YML, CONFLUENCE_YML, BITBUCKET_YML, JSM_YML, CROWD_YML
3+
from util.project_paths import JIRA_YML, CONFLUENCE_YML, BITBUCKET_YML, JSM_YML, CROWD_YML, BAMBOO_YML
44

55
TOOLKIT_VERSION = '4.3.0'
66

@@ -94,8 +94,18 @@ def __init__(self, config_yml):
9494
self.ramp_up = self.get_property('ramp-up')
9595

9696

97+
class BambooSettings(BaseAppSettings):
98+
99+
def __init__(self, config_yml):
100+
super().__init__(config_yml)
101+
self.concurrency = self.get_property('concurrency')
102+
self.total_actions_per_hour = self.get_property('total_actions_per_hour')
103+
self.ramp_up = self.get_property('ramp-up')
104+
105+
97106
JIRA_SETTINGS = JiraSettings(config_yml=JIRA_YML)
98107
CONFLUENCE_SETTINGS = ConfluenceSettings(config_yml=CONFLUENCE_YML)
99108
BITBUCKET_SETTINGS = BitbucketSettings(config_yml=BITBUCKET_YML)
100109
JSM_SETTINGS = JsmSettings(config_yml=JSM_YML)
101110
CROWD_SETTINGS = CrowdSettings(config_yml=CROWD_YML)
111+
BAMBOO_SETTINGS = BambooSettings(config_yml=BAMBOO_YML)
Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
import random
2+
import string
3+
4+
import urllib3
5+
6+
from util.conf import BAMBOO_SETTINGS
7+
from util.api.bamboo_clients import BambooClient
8+
from util.project_paths import BAMBOO_BUILD_PLANS, BAMBOO_USERS
9+
10+
urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)
11+
12+
BUILD_PLANS = 'plans'
13+
USERS = 'users'
14+
DEFAULT_PASSWORD = 'password'
15+
16+
17+
def generate_random_string(length=20):
18+
return "".join([random.choice(string.ascii_lowercase) for _ in range(length)])
19+
20+
21+
def get_users(client, users_count):
22+
existing_users = client.get_users(users_count)
23+
users_to_generate = 0
24+
users = []
25+
if len(existing_users) < users_count:
26+
users_to_generate = users_count - len(existing_users)
27+
users.extend(existing_users)
28+
if users_to_generate:
29+
for i in range(0, users_to_generate):
30+
username = f'performance_user_{generate_random_string(5)}'
31+
password = DEFAULT_PASSWORD
32+
generated_user = client.create_user(name=username, password=password)
33+
users.append(generated_user)
34+
return users
35+
36+
37+
def __create_dataset(client):
38+
dataset = dict()
39+
dataset[BUILD_PLANS] = client.get_build_plans(max_result=2000)
40+
dataset[USERS] = get_users(client, BAMBOO_SETTINGS.concurrency)
41+
return dataset
42+
43+
44+
def __write_to_file(file_path, items):
45+
with open(file_path, 'w') as f:
46+
for item in items:
47+
f.write(f"{item}\n")
48+
49+
50+
def write_test_data_to_files(dataset):
51+
build_plans = [f"{build_plan['searchEntity']['projectName']},{build_plan['id']}" for
52+
build_plan in dataset[BUILD_PLANS]]
53+
__write_to_file(BAMBOO_BUILD_PLANS, build_plans)
54+
users = [f"{user['name']},{DEFAULT_PASSWORD}" for user in dataset[USERS] if user['name'] != 'admin']
55+
__write_to_file(BAMBOO_USERS, users)
56+
57+
58+
def main():
59+
print("Started preparing data")
60+
61+
url = BAMBOO_SETTINGS.server_url
62+
print("Server url: ", url)
63+
64+
client = BambooClient(url, BAMBOO_SETTINGS.admin_login, BAMBOO_SETTINGS.admin_password,
65+
verify=BAMBOO_SETTINGS.secure)
66+
67+
dataset = __create_dataset(client)
68+
write_test_data_to_files(dataset)
69+
70+
print("Finished preparing data")
71+
72+
73+
if __name__ == "__main__":
74+
main()

app/util/project_paths.py

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,14 @@ def __get_crowd_dataset(file_name):
5555
return __get_crowd_datasets() / file_name
5656

5757

58+
def __get_bamboo_yml():
59+
return Path(__file__).parents[1] / "bamboo.yml"
60+
61+
62+
def __get_bamboo_datasets():
63+
return __get_datasets() / "bamboo"
64+
65+
5866
def __get_confluence_datasets():
5967
return __get_datasets() / "confluence"
6068

@@ -63,6 +71,10 @@ def __get_confluence_dataset(file_name):
6371
return __get_confluence_datasets() / file_name
6472

6573

74+
def __get_bamboo_dataset(file_name):
75+
return __get_bamboo_datasets() / file_name
76+
77+
6678
def __get_bitbucket_dataset(file_name):
6779
return __get_bitbucket_datasets() / file_name
6880

@@ -121,6 +133,11 @@ def __get_default_test_actions():
121133
CROWD_DATASETS = __get_crowd_datasets()
122134
CROWD_USERS = __get_crowd_dataset('users.csv')
123135

136+
BAMBOO_YML = __get_bamboo_yml()
137+
BAMBOO_DATASETS = __get_bamboo_datasets()
138+
BAMBOO_BUILD_PLANS = __get_bamboo_dataset('build_plans.csv')
139+
BAMBOO_USERS = __get_bamboo_dataset('users.csv')
140+
124141

125142
DEFAULT_TEST_ACTIONS = __get_default_test_actions()
126143
ENV_TAURUS_ARTIFACT_DIR = __get_taurus_artifacts_dir()

0 commit comments

Comments
 (0)