Removed Moodle specific load tests and Travis CI content.

This commit is contained in:
Umakanth Puppala 2018-10-15 17:54:05 -07:00
Родитель f5e7dac3b0
Коммит c8bebff00a
20 изменённых файлов: 0 добавлений и 9182 удалений

Просмотреть файл

@ -1,28 +0,0 @@
{
"esnext": true,
"node": true,
"browser": true,
"nomen": false,
"bitwise": true,
"eqeqeq": true,
"forin": true,
"immed": true,
"latedef": true,
"newcap": true,
"noarg": true,
"noempty": true,
"nonew": true,
"plusplus": true,
"regexp": true,
"undef": true,
"unused": true,
"trailing": true,
"indent": 4,
"esnext": true,
"onevar": true,
"white": true,
"quotmark": "double",
"predef": {
}
}

Просмотреть файл

@ -1,29 +0,0 @@
dist: trusty
language: python
node_js: "0.12"
python: "3.5"
cache:
- directories: node_modules
- pip
env:
- PYTHONUNBUFFERED=TRUE
install:
- npm install # Install task runners for lint checking.
- pip install azure-mgmt-subscription azure-mgmt-resource keyring pycurl # Install Azure Python SDK (we only need the sub & the resource manager packages)
before_script:
- ssh-keygen -q -f azure_moodle_id_rsa -N "" # Generate SSH keys to send to deployment
script:
- npm test
- ./etc/travis.py
notifications:
webhooks: https://outlook.office.com/webhook/e75ee820-3466-49a6-bb0f-ecae0daf8fe1@72f988bf-86f1-41af-91ab-2d7cd011db47/TravisCI/00abc9d7ce1044818f216da49d30d54d/a38fc8f6-fb60-4169-bde6-dd2bbf01304f

Просмотреть файл

@ -1,7 +0,0 @@
#!/bin/bash
from=$1
to=$2
sed -i s/%2F${from}%2F/%2F${to}%2F/g README.md
sed -i s#/${from}/#/${to}/#g azuredeploy.json

Просмотреть файл

@ -1,58 +0,0 @@
# Ensure that the Base URL for templates, scripts and deploy to Azure buttons
# is correctly set for the current git branch.
# Correct values for locations
CURRENT_BRANCH=$(git branch | sed -n -e 's/^\* \(.*\)/\1/p')
echo "Current git branch is '$CURRENT_BRANCH'"
BASE_TEMPLATE_URL=https://raw.githubusercontent.com/Azure/Moodle/$CURRENT_BRANCH/nested/
echo "Base template URL: $BASE_TEMPLATE_URL"
SCRIPT_LOCATION=https://raw.githubusercontent.com/Azure/Moodle/$CURRENT_BRANCH/scripts/
echo "Script location: $SCRIPT_LOCATION"
DEPLOY_TO_AZURE_URL=https://portal.azure.com/#create/Microsoft.Template/uri/https%3A%2F%2Fraw.githubusercontent.com%2FAzure%2FMoodle%2F$CURRENT_BRANCH%2Fazuredeploy.json
echo "Deploy to Azure URL: $DEPLOY_TO_AZURE_URL"
VISUALIZE_URL=http://armviz.io/#/?load=https%3A%2F%2Fraw.githubusercontent.com%2FAzure%2FMoodle%2F$CURRENT_BRANCH%2Fazuredeploy.json
echo "Visualize template URL: $VISUALIZE_URL"
# Check values in README.md
VALUE=$(sed -n -e 's/.*deploybutton.png)](\([^)]*\)).*/\1/p' README.md)
if [[ "$VALUE" = "$DEPLOY_TO_AZURE_URL" ]]
then
echo "Deploy to Azure URL is set correctly"
else
echo "!!!!! Deploy to Azure URL is not set correctly in README.md, it is currently:"
echo $VALUE
fi
VALUE=$(sed -n -e 's/.*visualizebutton.png)](\([^)]*\)).*/\1/p' README.md)
if [[ "$VALUE" = "$VISUALIZE_URL" ]]
then
echo "Visualize URL is set correctly"
else
echo "!!!!! Visualize URL is not set correctly in README.md, it is currently:"
echo $VALUE
fi
# Check values in azuredeploy.json
VALUE=$(sed -n -e 's/.*\"baseTemplateUrl\": \"\([^\"]*\)\",/\1/p' azuredeploy.json)
if [[ "$VALUE" = "$BASE_TEMPLATE_URL" ]]
then
echo "baseTemplateURL is set correctly"
else
echo "!!!!! baseTemplateURL is not set correctly, it is currently:"
echo $VALUE
fi
VALUE=$(sed -n -e 's/.*\"scriptLocation\": \"\([^\"]*\)\",/\1/p' azuredeploy.json)
if [[ "$VALUE" = "$SCRIPT_LOCATION" ]]
then
echo "scriptLocation is set correctly"
else
echo "!!!!! scriptLocation is not set correctly, it is currently:"
echo $VALUE
fi

Просмотреть файл

@ -1,163 +0,0 @@
#!/bin/bash
# Based on https://github.com/Azure/azure-quickstart-templates/blob/master/201-vmss-ubuntu-web-ssl/keyvault.sh
#set -e
usage()
{
echo usage: keyvault.sh '<keyvaultname> <resource group name> <location> <secretname> <certpemfile> <keypemfile> <cacertpemfile>'
echo The cacertpem file is optional. The template will accept a self-signed cert and key.
}
creategroup()
{
local group=$(az group show -g $rgname)
if [ -n "$group" ]; then
echo Resource Group $rgname already exists. Skipping creation.
else
# Create a resource group for the keyvault
az group create -n $rgname -l $location
fi
}
createkeyvault()
{
az keyvault show -n $vaultname 2> /dev/null
if [ $? -eq 0 ]
then
echo Key Vault $vaultname already exists. Skipping creation.
else
echo Creating Key Vault $vaultname.
creategroup
# Create the key vault
az keyvault create --name $vaultname --resource-group $rgname --location $location --enabled-for-template-deployment true --enabled-for-deployment true
fi
}
convertcert()
{
local cert=$1
local key=$2
local pfxfile=$3
local pass=$4
echo Creating PFX $pfxfile
openssl pkcs12 -export -out $pfxfile -inkey $key -in $cert -password pass:$pass 2> /dev/null
if [ $? -eq 1 ]
then
echo problem converting $key and $cert to pfx
exit 1
fi
fingerprint=$(openssl x509 -in $cert -noout -fingerprint | cut -d= -f2 | sed 's/://g' )
}
convertcacert()
{
local cert=$1
local pfxfile=$2
local pass=$3
echo Creating PFX $pfxfile
openssl pkcs12 -export -out $pfxfile -nokeys -in $cert -password pass:$pass 2> /dev/null
if [ $? -eq 1 ]
then
echo problem converting $cert to pfx
exit 1
fi
fingerprint=$(openssl x509 -in $cert -noout -fingerprint | cut -d= -f2 | sed 's/://g' )
}
storesecret()
{
local secretfile=$1
local name=$2
filecontentencoded=$( cat $secretfile | base64 $base64_unwrap )
json=$(cat << EOF
{
"data": "${filecontentencoded}",
"dataType" :"pfx",
"password": "${pwd}"
}
EOF
)
jsonEncoded=$( echo $json | base64 $base64_unwrap )
r=$(az keyvault secret set --vault-name $vaultname --name $name --value $jsonEncoded)
if [ $? -eq 1 ]
then
echo problem storing secret $name in $vaultname
exit 1
fi
id=$(az keyvault secret show --vault-name $vaultname --name $name --query id -o tsv)
echo Secret ID is $id
}
# We need at least 6 parameters
if [ "$#" -lt 6 ]; then
usage
exit
fi
# The base64 command on OSX does not know about the -w parameter, but outputs unwrapped base64 by default
base64_unwrap="-w 0"
[[ $(uname) == "Darwin" ]] && base64_unwrap=""
vaultname=$1
rgname=$2
location=$3
secretname=$4
certfile=$5
keyfile=$6
cacertfile=$7
# Create a random password with 33 bytes of entropy
# I picked 33 so the last character will not be =
pwd=$(dd if=/dev/urandom bs=32 count=1 2>/dev/null | base64)
certpfxfile=${certfile%.*crt}.pfx
cacertpfxfile=${cacertfile%.*crt}.pfx
casecretname=ca$secretname
createkeyvault
# converting SSL cert to pfx
convertcert $certfile $keyfile $certpfxfile $pwd
certprint=$fingerprint
echo $certpfxfile fingerprint is $fingerprint
# storing pfx in keyvault
echo Storing $certpfxfile as $secretname
storesecret $certpfxfile $secretname
certid=$id
rm -f $certpfxfile
if [ ! -z $cacertfile ]
then
# converting CA cert to pfx
convertcacert $cacertfile $cacertpfxfile $pwd
echo $cacertpfxfile fingerprint is $fingerprint
cacertprint=$fingerprint
# storing pfx in key vault
echo Storing $cacertpfxfile as $casecretname
storesecret $cacertpfxfile $casecretname
cacertid=$id
rm -f $cacertpfxfile
fi
echo "Specified SSL cert/key .pem files are now stored in your Azure Key Vault and ready to be used by the template."
echo "Use the following values for the related template parameters:"
echo
echo "- keyVaultResourceId: $(az keyvault show --name $vaultname --query id -o tsv)"
echo "- sslCertKeyVaultURL: $certid"
echo "- sslCertThumbprint: $certprint"
echo "- caCertKeyVaultURL: $cacertid"
echo "- caCertThumbprint: $cacertprint"
echo Done

Просмотреть файл

@ -1,5 +0,0 @@
#!/usr/bin/env python3
from travis.DeploymentTester import DeploymentTester
DeploymentTester().run()

Просмотреть файл

@ -1,85 +0,0 @@
import json
import os
import time
from azure.mgmt.resource.resources.v2017_05_10.models import DeploymentMode
class Configuration:
def __init__(self):
self.deployment_name = 'azuredeploy'
self.client_id = os.getenv('SPNAME')
self.secret = os.getenv('SPPASSWORD')
self.tenant_id = os.getenv('SPTENANT')
self.location = os.getenv('LOCATION', 'westus2')
self.source_branch = self.identify_source_branch()
self.fullci_branches = os.getenv('FULLCI_BRANCHES', 'master').split(':')
self.commit_message = os.getenv('TRAVIS_COMMIT_MESSAGE', None)
self.ssh_key = self.identify_ssh_key()
self.resource_group = self.identify_resource_group()
self.deployment_properties = self.generate_deployment_properties()
def identify_resource_group(self):
resource_group = os.getenv('RESOURCEGROUP')
if resource_group is None:
resource_group = 'azmdl-travis-' + os.getenv('TRAVIS_BUILD_NUMBER', 'manual-{}'.format(time.time()))
return resource_group
def identify_ssh_key(self):
ssh_key = os.getenv('SPSSHKEY')
if ssh_key is None:
with open('azure_moodle_id_rsa.pub', 'r') as sshkey_fd:
ssh_key = sshkey_fd.read()
return ssh_key
def generate_deployment_properties(self):
with open('azuredeploy.json', 'r') as template_fd:
template = json.load(template_fd)
with open('azuredeploy.parameters.json', 'r') as parameters_fd:
parameters = json.load(parameters_fd)
parameters = parameters['parameters']
parameters['sshPublicKey']['value'] = self.ssh_key
parameters['_artifactsLocation'] = {'value': self.identify_artifacts_location()}
return {
'mode': DeploymentMode.incremental,
'template': template,
'parameters': parameters,
}
def identify_artifacts_location(self):
slug = os.getenv('TRAVIS_PULL_REQUEST_SLUG')
if not slug:
slug = os.getenv('TRAVIS_REPO_SLUG')
return "https://raw.githubusercontent.com/{}/{}/".format(slug, self.source_branch)
def identify_source_branch(self):
branch = os.getenv('TRAVIS_PULL_REQUEST_BRANCH')
if not branch:
branch = os.getenv('TRAVIS_BRANCH')
return branch
def is_valid(self):
valid = True
for key, value in vars(self).items():
if value is None:
valid = False
print('(missing configuration for {})'.format(key))
if self.deployment_properties['parameters']['_artifactsLocation']['value'] is None:
valid = False
print('(could not identify _artifactsLocation)')
return valid
def should_run_full_ci(self):
if self.source_branch in self.fullci_branches:
return True
message = self.commit_message.upper()
if '[FULL CI]' in message or '[FULLCI]' in message:
return True
return False

Просмотреть файл

@ -1,177 +0,0 @@
import os
import pycurl
import sys
import tempfile
import time
import urllib
from io import BytesIO
from pycurl import Curl
from azure.mgmt.resource import ResourceManagementClient
from azure.mgmt.subscription import SubscriptionClient
from msrestazure.azure_active_directory import ServicePrincipalCredentials
from travis.Configuration import Configuration
class DeploymentTester:
@staticmethod
def elapsed(since):
elapsed = int(time.time() - since)
elapsed = '{:02d}:{:02d}:{:02d}'.format(elapsed // 3600, (elapsed % 3600 // 60), elapsed % 60)
return elapsed
def __init__(self):
self.config = Configuration()
self.deployment = None
self.credentials = None
""":type : ServicePrincipalCredentials"""
self.resource_client = None
""":type : ResourceManagementClient"""
def run(self):
should_delete_resource_group = False
try:
self.check_configuration()
self.login()
self.create_resource_group()
self.validate()
if not self.config.should_run_full_ci():
print('\n\nBasic CI tests successful.')
should_delete_resource_group = True
return
self.deploy()
self.moodle_smoke_test()
self.moodle_admin_login()
print('\n\nFull CI tests successful!')
should_delete_resource_group = True
finally:
if should_delete_resource_group:
self.delete_resource_group()
def check_configuration(self):
print('\nChecking configuration...')
if not self.config.is_valid():
print('No Azure deployment info given, skipping test deployment and exiting.')
print('Further information: https://github.com/Azure/Moodle#automated-testing-travis-ci')
sys.exit()
artifacts_location = self.config.deployment_properties['parameters']['_artifactsLocation']
print('- Detected "_artifactsLocation": ' + artifacts_location['value'])
print("(all check)")
def login(self):
print('\nLogging in...')
self.credentials = ServicePrincipalCredentials(
client_id=self.config.client_id,
secret=self.config.secret,
tenant=self.config.tenant_id,
)
print('(got credentials)')
subscription_client = SubscriptionClient(self.credentials)
subscription = next(subscription_client.subscriptions.list())
print('(found subscription)')
self.resource_client = ResourceManagementClient(self.credentials, subscription.subscription_id)
print("(logged in)")
def create_resource_group(self):
print('\nCreating group "{}" on "{}"...'.format(self.config.resource_group, self.config.location))
self.resource_client.resource_groups.create_or_update(self.config.resource_group,
{'location': self.config.location})
print('(created)')
def validate(self):
print('\nValidating template...')
validation = self.resource_client.deployments.validate(self.config.resource_group,
self.config.deployment_name,
self.config.deployment_properties)
if validation.error is not None:
print("*** VALIDATION FAILED ({}) ***".format(validation.error))
print(validation.error.message)
for detail in validation.error.details:
print("- {}:\n{}".format(detail.code, detail.message))
sys.exit(1)
print("(valid)")
def deploy(self):
print('\nDeploying template, feel free to take a nap...')
deployment = self.resource_client.deployments.create_or_update(self.config.resource_group,
self.config.deployment_name,
self.config.deployment_properties)
""":type : msrestazure.azure_operation.AzureOperationPoller"""
started = time.time()
while not deployment.done():
print('... after {} still "{}" ...'.format(self.elapsed(started), deployment.status()))
deployment.wait(60)
print("WAKE UP! After {} we finally got status {}.".format(self.elapsed(started), deployment.status()))
print("Checking deployment response...")
properties = deployment.result(0).properties
if properties.provisioning_state != 'Succeeded':
print("*** DEPLOY FAILED ***")
print('Provisioning state: ' + properties.provisioning_state)
sys.exit(1)
self.load_deployment_outputs(properties.outputs)
print("(success)")
def load_deployment_outputs(self, outputs):
self.deployment = {}
for key, value in outputs.items():
self.deployment[key] = value['value']
print("- Found: " + key)
def moodle_smoke_test(self):
print("\nMoodle Smoke Test...")
url = 'https://' + self.deployment['siteURL']
curl = Curl()
curl.setopt(pycurl.URL, url)
curl.setopt(pycurl.SSL_VERIFYPEER, False)
curl.setopt(pycurl.WRITEFUNCTION, lambda x: None)
curl.perform()
status = curl.getinfo(pycurl.HTTP_CODE)
if status != 200:
print("*** DEPLOY FAILED ***")
print('HTTP Status Code: {}'.format(status))
sys.exit(1)
print('(ok: {})'.format(status))
def moodle_admin_login(self):
print("\nLogging in into Moodle as 'admin'...")
response = self.moodle_admin_login_curl()
if 'Admin User' not in response:
print("*** FAILED: 'Admin User' keyword not found ***")
sys.exit(1)
print('(it worked)')
def moodle_admin_login_curl(self):
fd, path = tempfile.mkstemp()
try:
response = BytesIO()
url = 'https://' + self.deployment['siteURL'] + '/login/index.php'
curl = Curl()
curl.setopt(pycurl.URL, url)
curl.setopt(pycurl.SSL_VERIFYPEER, False)
curl.setopt(pycurl.WRITEFUNCTION, response.write)
curl.setopt(pycurl.POST, True)
curl.setopt(pycurl.COOKIEJAR, path)
curl.setopt(pycurl.COOKIEFILE, path)
post = urllib.parse.urlencode({'username': 'admin', 'password': self.deployment['moodleAdminPassword']})
curl.setopt(pycurl.POSTFIELDS, post)
curl.setopt(pycurl.FOLLOWLOCATION, True)
curl.perform()
status = curl.getinfo(pycurl.HTTP_CODE)
if status != 200:
print("*** FAILED: {} ***".format(status))
sys.exit(1)
response = response.getvalue().decode('utf-8')
finally:
os.remove(path)
return response
def delete_resource_group(self):
print('\n\nDeleting the resource group for this passing build...')
self.resource_client.resource_groups.delete(self.config.resource_group, polling=False)
print('(delete initiated, not polling)')

Просмотреть файл

Просмотреть файл

@ -1,9 +0,0 @@
#!/bin/bash
# Should be run at the git repo root as: $ ./etc/updateDocsParameters.sh
dpkg -l jq &> /dev/null || sudo apt install jq
sed -i '/## Available Parameters/q' docs/Parameters.md
echo >> docs/Parameters.md
jq -r '.parameters | to_entries[] | "### " + .key + "\n\n" + .value.metadata.description + "\n\nType: " + .value.type + "\n\nPossible Values: " + (.value.allowedValues | @text) + "\n\nDefault: " + (.value.defaultValue | @text) + "\n\n"' azuredeploy.json >> docs/Parameters.md

Просмотреть файл

@ -1,41 +0,0 @@
# Login to Azure
Before we start a load test session we need to first veriy that we are
logged in to Azure using the CLI.
## Azure Login
``` bash
az login --username $AZURE_USERNAME --password $AZURE_PASWORD
```
Note that if your username or password has any special characters in
it, such as '$' this may fail. You can login using a browser using `az login`.
``` bash
az account set --subscription $AZURE_SUBSCRIPTION_ID
```
## Validation
``` bash
az account show
```
Results:
```
{
"environmentName": "AzureCloud",
"id": "325e7c34-99fb-4190-aa87-1df746c67705",
"isDefault": true,
"name": "Ross Dev Account",
"state": "Enabled",
"tenantId": "72f988bf-86f1-41af-91ab-2d7cd011db47",
"user": {
"name": "rogardle@microsoft.com",
"type": "user"
}
}
```

Просмотреть файл

@ -1,125 +0,0 @@
# Setting up a test host
To run load tests using the resources in this directory, you'll want
to spin up an Ubuntu VM (let's call it the jMeter host) in your Azure
subscription. This should be located in the same region as your Moodle
cluster in order to avoid egress charges. Once your VM is ready, you
need to install Java and [jMeter](https://jmeter.apache.org/).
## Prerequisites
To make things consistent across different sessions load testing Moodle we
should [configure the moodle environment](../docs/Preparation.md).
We will want to use a consistent resource group name in order to avoid
wasting resource in these tests:
```
MOODLE_RG_NAME=loadtest
```
And we'll need a name for our load test VM:
```
MOODLE_LOAD_TEST_VM_NAME=LoadTestVM
```
## Deploy the Load Test VM
First you need a resource group within which all your resources will be deployed.
``` bash
az group create --name $MOODLE_RG_NAME --location $MOODLE_RG_LOCATION
```
Now we can create our VM in this group. The following command will
create the VM and, if necessary, generate the SSH keys.
``` bash
az vm create --resource-group $MOODLE_RG_NAME --name $MOODLE_LOAD_TEST_VM_NAME --image UbuntuLTS --generate-ssh-keys
```
Results:
``` json
{
"fqdns": "",
"id": "/subscriptions/325e7c34-99fb-4190-aa87-1df746c67705/resourceGroups/loadtestvm/providers/Microsoft.Compute/virtualMachines/LoadTestVM",
"location": "southcentralus",
"macAddress": "00-0D-3A-70-91-57",
"powerState": "VM running",
"privateIpAddress": "10.0.0.4",
"publicIpAddress": "13.84.131.173",
"resourceGroup": "loadtestvm",
"zones": ""
}
```
You will need the IP number from this output. For convenience we'll
place it into an environment variable:
``` bash
ipAddress=$(az network public-ip show --name ${MOODLE_LOAD_TEST_VM_NAME}PublicIP --resource-group $MOODLE_RG_NAME --query "ipAddress" --output tsv)
echo $ipAddress
```
We can now connect to the VM using ssh, and run commands. The first thing we want to do is pull down the Moodle on Azure repo. Since this document is used to automatically run tests all our commands need to be non-interactive. We will therefore skip the host key validation step. Note that you should never do this in a production environment (remove `-o StrictHostKeyChecking=no`):
``` bash
ssh -o StrictHostKeyChecking=no $ipAddress "rm -Rf Moodle; git clone git://github.com/Azure/Moodle.git"
```
Now we can install the load testing scripts, we will have these loaded
via the `.profile` so that they are always availble.
``` bash
ssh $ipAddress 'echo ". ~/Moodle/loadtest/loadtest.sh" >> ~/.profile'
```
This script provides some helper functions for installing dependencies
on the VM.
``` bash
ssh $ipAddress 'install_java_and_jmeter; install_az_cli'
```
We need to login to Azure using the CLI. The command below is
convenient but is not secure since it stores your password in clear
text in an environment variable. However, it is convenient for test
purposes.
``` bash
ssh $ipAddress "az login --username $AZURE_LOGIN --password $AZURE_PASSWORD; az account set --subscription $AZURE_SUBSCRIPTION_ID"
```
## Validation
Finally, we will verify that key dependencies have been installed. First lets check Java is present:
``` bash
ssh -o StrictHostKeyChecking=no $ipAddress "java -version"
```
Results:
```
openjdk version "1.8.0_151"
OpenJDK Runtime Environment (build 1.8.0_151-8u151-b12-0ubuntu0.16.04.2-b12)
OpenJDK 64-Bit Server VM (build 25.151-b12, mixed mode)
```
We will also need to confirm the Azure CLI is present:
``` bash
ssh -o StrictHostKeyChecking=no $ipAddress "if hash az 2>/dev/null; then echo "Azure CLI Installed"; else echo "Missing dependency: Azure CLI"; fi"
```
Results:
```
Azure CLI Installed
```

Просмотреть файл

@ -1,139 +0,0 @@
# Load-Testing Deployed Moodle Cluster
This directory currently contains utility scripts, a Moodle test
course, and an Apache jMeter test plan that can be used to load-test a
Moodle cluster on Azure using the Azure Resource Manager templates in
this repository.
## Prerequisites
To run load tests using the resources in this directory, you'll want
to spin up a VM to manage the [Load Test](Deploy_Load_Test_VM.md) in
your Azure subscription. This VM will generate the traffic, running it
in Azure will minimize network charges.
## Deploying Moodle using templates and running load test
Once dependencies are installed, you can initiate the load testing
process by using included utility scripts. These scripts will:
* deploy a Moodle cluster
* set up the test course in Moodle
* enrol students for the course
* run a synthetic test workload using jMeter
* teardown the test cluster
Use the function `deploy_run_test1_teardown` to perform all these
steps. This function takes 18 parameters in the following order:
See the included example `run_load_test_example` in
`loadtest/loadtest.sh`. At the time of writing this example is
configured as follows:
``` bash
ssh $ipAddress "az login --username $AZURE_LOGIN --password $AZURE_PASSWORD; az account set --subscription $AZURE_SUBSCRIPTION_ID; run_load_test_example"
```
Running this example will deploy a cluster with the following configuration:
* Apache web server
* Standard_DS2_v2 Azure VM SKU
* mysql database (with 200 DTU and 125GB DB size)
* NFS file share (with 2 disks and 128GB disk size each)
* uses your SSH pub key in `~/.ssh/id_rsa`
[NOTE ON SSH KEYS] Ensure your `~/.ssh/id_rsa` has been added to ssh-agent using `eval $(ssh-agent)` and `ssh-add`).
Once the Moodle cluster is deployed and configured with course and
student data (using [moosh](https://moosh-online.com/) it will run the
synthetic workload with designated number of concurrent threads (in
the example we use 1600 thread) for the designated duration and rampup
time (18000 seconds = 5 hours duration, 4800 seconds rampup time in
the example).
## Test plans
We'd like to offer test plans that are as realistic as possible, so that potential
Moodle users on Azure can have better confidence with their Moodle deployment on Azure.
We are just starting out in that direction and here are descriptions of currently
available test plans.
### Simple Scenario [simple-test-1.jmx](./simple-test-1.jmx)
This test plan is a simple scenario that performs the following operations repeatedly:
* Login to the Moodle site
* View the test course
* View any resource if any
* View a forum in the test course
* View any forum discussion
* Post a new discussion topic
* Take a quiz and submit
The scripts in [loadtest.sh](./loadtest.sh) are tailored for this test plan.
### Moodle Data Stress Testing [simple-test-2.jmx](./simple-test-2.jmx)
Currently [loadtest.sh](./loadtest.sh) doesn't have any tailored scripts for this
test plan. Therefore, this test plan will need to be executed by issuing the
actual jmeter command with properly modified parameters manually, or it'd be
greatly appreciated if someone can contribute better support for this test plan
in [loadtest.hs](./loadtest.sh).
The purpose of this test plan is to try stressing the moodledata directory
in a shared file system (either a gluster volume or an NFS share, depending
on the choice). Initially attaching a random file in a forum discussion post
was tried, but for some reason (probably due to my lack of understanding
in PHP/web interaction), files were not attached. I instead tried to upload
random files to each test Moodle users's Private Files area, and it did work.
This test plan basically performs the following operations repeatedly:
* Login to the Moodle site
* Open the Moodle user's Private Files repository
* Upload a randomly generated file (of a random size within a hard-coded range)
* Save the change
This way, we were able to populate the shared moodledata directory with
random files in Moodle users' Private Files repositories. The mechanism
to generate random files is not so efficient, so that's currently what
slows down the upload speed, and any improvement in that BeanShell preprocessor
code would be great. Note that the uploaded files have to be different.
Moodle seems so good at deduplicating that a single file uploaded multiple
times by different users won't increase the file system usage beyond its
single copy.
It'd be also great if we add a download operation step in the test plan,
and it's left as a future work item.
### Latency-Sensitive Stress Testing [time-gated-exam-test.jmx](./time-gated-exam-test.jmx)
This test stresses the deployed Moodle cluster with 1000 emulated students
trying to get in an exam (quiz) that's initially closed and will be opened
at the designated exam start time (have to be manually set on the test course's
corresponding quiz's Settings). Once the exam start time passes, each emulated
student continues taking the exam for 10 times.
This test has been used to find out how responsive
a deployed Moodle cluster can be on very latency-sensitive workloads. We've been
using this test with different file server types to find out which file server
type offers best response times.
## Please contribute
It'd be great if we have more test plans, and make other parameters configurable (for
example, make the auto-scaling thresholds configurable, which actually requires
some changes in the templates as well). The currently available test plans
also have hard-coded database type (JDBC connection string) that won't work
for Postgres SQL server, so making it work would be also greatly appreciated.
Also, if you run this load test with any parameters, it'd be great to share
the numeric results so that we can have more performance data on various
configurations. Here is [a link to an Excel spreadsheet](https://1drv.ms/x/s!Aj6KpM6lFGAjgd4D6IV8_6M42q9omA)
where anyone can share their load testing results.
## Acknowledgement
The original test course and the test plan were generously provided by
[Catalyst](https://github.com/catalyst) as part of this template modernization
project. jMeter is a great load testing tool, and also thanks to [moosh](http://moosh-online.com/),
the whole process could be automated without too much difficulty, which was
really nice.

Просмотреть файл

@ -1,16 +0,0 @@
{
"$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentParameters.json#",
"contentVersion": "1.0.0.0",
"parameters": {
"autoscaleVmSku": { "value": "__WEB_VM_SKU__" },
"dbServerType": { "value": "__DB_SERVER_TYPE__" },
"mysqlPgresVcores": { "value": 2 },
"mysqlPgresStgSizeGB": { "value": 125 },
"webServerType": { "value": "__WEB_SERVER_TYPE__" },
"fileServerType": { "value": "__FILE_SERVER_TYPE__" },
"fileServerDiskCount": { "value": 2 },
"fileServerDiskSize": { "value": 128 },
"redisDeploySwitch": { "value": false },
"sshPublicKey": { "value": "__SSH_PUB_KEY__" }
}
}

Просмотреть файл

@ -1,326 +0,0 @@
#!/bin/bash
# This is not fully tested. Just documenting what's needed.
function install_java_and_jmeter
{
sudo apt update || return 1
sudo apt install -y openjdk-8-jdk || return 1
wget -O apache-jmeter-4.0.tgz http://www-us.apache.org/dist/jmeter/binaries/apache-jmeter-4.0.tgz || return 1
tar xfz apache-jmeter-4.0.tgz -C ~
mkdir -p ~/bin
ln -s ~/apache-jmeter-4.0/bin/jmeter ~/bin/jmeter
rm apache-jmeter-4.0.tgz
wget -O mysql-connector-java-5.1.45.tar.gz https://dev.mysql.com/get/Downloads/Connector-J/mysql-connector-java-5.1.45.tar.gz || return 1
tar xfz mysql-connector-java-5.1.45.tar.gz
mv mysql-connector-java-5.1.45/mysql-connector-java-5.1.45-bin.jar ~/apache-jmeter-4.0/lib
rm -rf mysql-connector-java-5.1.45*
wget -O postgres-42.2.1.jar https://jdbc.postgresql.org/download/postgresql-42.2.1.jar || return 1
mv postgres-42.2.1.jar ~/apache-jmeter-4.0/lib
# Have to have jmeter plugins manager and have it download the needed plugins in advance...
wget -O jmeter-plugins-manager-0.19.jar http://search.maven.org/remotecontent?filepath=kg/apc/jmeter-plugins-manager/0.19/jmeter-plugins-manager-0.19.jar || return 1
mv jmeter-plugins-manager-0.19.jar ~/apache-jmeter-4.0/lib/ext
wget -O cmdrunner-2.0.jar http://search.maven.org/remotecontent?filepath=kg/apc/cmdrunner/2.0/cmdrunner-2.0.jar || return 1
mv cmdrunner-2.0.jar ~/apache-jmeter-4.0/lib
java -cp ~/apache-jmeter-4.0/lib/ext/jmeter-plugins-manager-0.19.jar org.jmeterplugins.repository.PluginManagerCMDInstaller
# TODO Hard-coded .jmx file here. Do this for each individual .jmx file
wget -O tmp-for-plugin-install.jmx https://raw.githubusercontent.com/Azure/Moodle/master/loadtest/simple-test-1.jmx || return 1
~/apache-jmeter-4.0/bin/PluginsManagerCMD.sh install-for-jmx tmp-for-plugin-install.jmx
rm tmp-for-plugin-install.jmx
}
function install_az_cli
{
local az_repo=$(lsb_release -cs)
echo "deb [arch=amd64] https://packages.microsoft.com/repos/azure-cli/ $az_repo main" | sudo tee /etc/apt/sources.list.d/azure-cli.list
sudo apt-key adv --keyserver packages.microsoft.com --recv-keys 52E16F86FEE04B979B07E28DB02C46DF417A0893
sudo apt-get install -y apt-transport-https || return 1
sudo apt-get update && sudo apt-get install -y azure-cli || return 1
}
function check_if_logged_on_azure
{
az account show --query id -o tsv > /dev/null 2>&1
if [ $? != "0" ]; then
echo "Not logged on to Azure. Run 'az login' first and make sure subscription is set to your desired one."
return 1
fi
}
function show_command_to_run
{
echo "Running command: $*"
}
function check_db_sku_params
{
local vcores=${1}
local size=${2} # In GB
if [ "$vcores" != 1 -a "$vcores" != 2 -a "$vcores" != 4 -a "$vcores" != 8 -a "$vcores" != 16 -a "$vcores" != 32 ]; then
echo "Invalid vCores ($vcores). Only allowed are 1, 2, 4, 8, 16, 32."
return 1
fi
if [ -z "${size##*[!0-9]*}" ] || [ "$size" -lt 5 ] || [ "$size" -gt 1024 ]; then
echo "Invalid DB size ($size). Only allowed are 5, 6, 7, ..., 1024."
return 1
fi
# TODO Add other SKU params: Tiers (Basic/GeneralPurpose/MemoryOptimized), HW family (Gen4/Gen5)
}
# TODO hard-coded Azure location in global variable. Parametrize this later.
MOODLE_RG_LOCATION=southcentralus
function deploy_moodle_with_some_parameters
{
check_if_logged_on_azure || return 1
local resource_group=${1} # Azure resource group where templates will be deployed
local template_url=${2} # Github URL of the top template to deploy
local parameters_template_file=${3} # Local parameter template file
local web_server_type=${4} # E.g., apache or nginx
local web_vm_sku=${5} # E.g., Standard_DS2_v2
local db_server_type=${6} # E.g., mysql or postgres
local db_vcores=${7} # 1, 2, 4, 8, 16, 32 only
local db_size_gb=${8} # 5 to 1024, integer only
local file_server_type=${9} # E.g., nfs or gluster
local file_server_disk_count=${10} # 2, 3, 4
local file_server_disk_size=${11} # in GB
local redis_cache=${12} # Redis cache choice. Currently 'true' or 'false' only.
local ssh_pub_key=${13} # Your ssh authorized_keys content
local no_wait_flag=${14} # Must be "--no-wait" to be passed to az
check_db_sku_params $db_vcores $db_size_gb || return 1
local cmd="az group create --resource-group $resource_group --location $MOODLE_RG_LOCATION"
show_command_to_run $cmd
eval $cmd || return 1
local deployment_name="${resource_group}-deployment"
local cmd="az group deployment create --resource-group $resource_group --name $deployment_name $no_wait_flag --template-uri $template_url --parameters @$parameters_template_file webServerType=$web_server_type autoscaleVmSku=$web_vm_sku dbServerType=$db_server_type mysqlPgresVcores=$db_vcores mysqlPgresStgSizeGB=$db_size_gb fileServerType=$file_server_type fileServerDiskCount=$file_server_disk_count fileServerDiskSize=$file_server_disk_size redisDeploySwitch=$redis_cache sshPublicKey='$ssh_pub_key'"
show_command_to_run $cmd
eval $cmd
}
function delete_resource_group
{
check_if_logged_on_azure || return 1
local resource_group=${1}
local cmd="az group delete --resource-group $resource_group"
show_command_to_run $cmd
eval $cmd
}
function install_moosh
{
# 'composer install' keeps failing, so try apt...
sudo apt-add-repository 'deb http://ppa.launchpad.net/zabuch/ppa/ubuntu trusty main'
sudo apt-get update || true
sudo apt-get install -y --allow-unauthenticated moosh
# sudo apt update || return 1
# sudo apt install -y composer || return 1
# cd ~
# git clone git://github.com/tmuras/moosh.git || return 1
# cd moosh
# composer install || sleep 30 && composer install || sleep 30 && composer install || return 1
# mkdir -p ~/bin
# ln -s $PWD/moosh.php ~/bin/moosh
}
MOODLE_PATH=/moodle/html/moodle
function delete_course
{
local course_id=${1}
sudo -u www-data moosh --moodle-path=$MOODLE_PATH course-delete $course_id
}
function create_course
{
local course_id=${1}
sudo -u www-data moosh --moodle-path=$MOODLE_PATH course-create --idnumber=$course_id empty@test.course
}
function restore_course_from_url
{
local url=${1}
wget $url -O backup_to_restore.mbz
sudo -u www-data moosh --moodle-path=$MOODLE_PATH course-restore backup_to_restore.mbz 1
}
function create_2000_test_users_and_enroll_them_in_course
{
local course_id=${1}
local password=${2}
# TODO ugly...
sudo -u www-data moosh --moodle-path=$MOODLE_PATH user-create -p $password m_azuretestuser_{1..200}
sudo -u www-data moosh --moodle-path=$MOODLE_PATH user-create -p $password m_azuretestuser_{201..400}
sudo -u www-data moosh --moodle-path=$MOODLE_PATH user-create -p $password m_azuretestuser_{401..600}
sudo -u www-data moosh --moodle-path=$MOODLE_PATH user-create -p $password m_azuretestuser_{601..800}
sudo -u www-data moosh --moodle-path=$MOODLE_PATH user-create -p $password m_azuretestuser_{801..1000}
sudo -u www-data moosh --moodle-path=$MOODLE_PATH user-create -p $password m_azuretestuser_{1001..1200}
sudo -u www-data moosh --moodle-path=$MOODLE_PATH user-create -p $password m_azuretestuser_{1201..1400}
sudo -u www-data moosh --moodle-path=$MOODLE_PATH user-create -p $password m_azuretestuser_{1401..1600}
sudo -u www-data moosh --moodle-path=$MOODLE_PATH user-create -p $password m_azuretestuser_{1601..1800}
sudo -u www-data moosh --moodle-path=$MOODLE_PATH user-create -p $password m_azuretestuser_{1801..2000}
sudo -u www-data moosh --moodle-path=$MOODLE_PATH course-enrol $course_id m_azuretestuser_{1..200}
sudo -u www-data moosh --moodle-path=$MOODLE_PATH course-enrol $course_id m_azuretestuser_{201..400}
sudo -u www-data moosh --moodle-path=$MOODLE_PATH course-enrol $course_id m_azuretestuser_{401..600}
sudo -u www-data moosh --moodle-path=$MOODLE_PATH course-enrol $course_id m_azuretestuser_{601..800}
sudo -u www-data moosh --moodle-path=$MOODLE_PATH course-enrol $course_id m_azuretestuser_{801..1000}
sudo -u www-data moosh --moodle-path=$MOODLE_PATH course-enrol $course_id m_azuretestuser_{1001..1200}
sudo -u www-data moosh --moodle-path=$MOODLE_PATH course-enrol $course_id m_azuretestuser_{1201..1400}
sudo -u www-data moosh --moodle-path=$MOODLE_PATH course-enrol $course_id m_azuretestuser_{1401..1600}
sudo -u www-data moosh --moodle-path=$MOODLE_PATH course-enrol $course_id m_azuretestuser_{1601..1800}
sudo -u www-data moosh --moodle-path=$MOODLE_PATH course-enrol $course_id m_azuretestuser_{1801..2000}
}
function hide_course_overview_block_for_jmeter_test
{
# "myoverview" is the registered name of the "Course overview" block
sudo -u www-data moosh --moodle-path=$MOODLE_PATH block-manage hide myoverview
}
# TODO hard-coded values...
LOADTEST_BASE_URI=https://raw.githubusercontent.com/Azure/Moodle/master/loadtest
MOODLE_TEST_USER_PASSWORD='testUserP@$$w0rd'
function setup_test_course_and_users
{
install_moosh
# TODO hard-coded test course backup location
restore_course_from_url $LOADTEST_BASE_URI/moodle-on-azure-test-course-1.mbz
local course_id=2 # TODO Fix this hard-coded course id #. Should be retrieved from the previous restore_course_from_url output
local password=$MOODLE_TEST_USER_PASSWORD # TODO parameterize
create_2000_test_users_and_enroll_them_in_course $course_id $password
hide_course_overview_block_for_jmeter_test
}
function run_cmd_on_remote_host
{
local func_cmd=${1} # E.g., install_moosh or 'delete_course 2'
local ssh_dest=${2} # E.g., azureadmin@10.2.3.4
local port=${3:-22} # E.g., 2222
local cmd="ssh -o 'StrictHostKeyChecking no' -p $port $ssh_dest 'wget $LOADTEST_BASE_URI/loadtest.sh -O loadtest.sh; source loadtest.sh; $func_cmd'"
show_command_to_run $cmd
eval $cmd
}
function run_simple_test_1_on_resource_group
{
local resource_group=${1} # Azure resource group where Moodle templates were deployed
local test_threads_count=${2} # E.g., 400, 800, ...
local test_rampup_time_sec=${3} # E.g., 900 (should be long enough for # threads above)
local test_run_time_sec=${4} # E.g., 3600 for 1 hour
local setup_test_course_users_flag=${5} # Run setup_test_course_and_users on moodle_host if nonzero
sudo apt update; sudo apt install -y jq
local deployment="${resource_group}-deployment"
local output=$(az group deployment show -g $resource_group -n $deployment)
local moodle_host=$(echo $output | jq -r .properties.outputs.siteURL.value)
local db_host=$(echo $output | jq -r .properties.outputs.databaseDNS.value)
local moodle_db_user=$(echo $output | jq -r .properties.outputs.moodleDbUsername.value)
local moodle_db_pass=$(echo $output | jq -r .properties.outputs.moodleDbPassword.value)
local moodle_user_pass=$MOODLE_TEST_USER_PASSWORD # TODO parameterize
if [ -n "$setup_test_course_users_flag" ]; then
local moodle_controller_ip=$(echo $output | jq -r .properties.outputs.controllerInstanceIP.value)
run_cmd_on_remote_host setup_test_course_and_users azureadmin@${moodle_controller_ip}
fi
mkdir -p test_outputs
local prefix="test_outputs/simple_test_1_$(date +%Y%m%d%H%M%S)"
echo $output | jq . > ${prefix}.deployment.json
export JVM_ARGS="-Xms1024m -Xmx4096m"
local cmd="jmeter -n -t simple-test-1.jmx -l ${prefix}.jmeter.results.txt -j ${prefix}.jmeter.log -e -o ${prefix}.jmeter.report -Jhost=${moodle_host} -Jdb_host=${db_host} -Jdb_user=${moodle_db_user} '-Jdb_pass=${moodle_db_pass}' '-Jmoodle_user_pass=${moodle_user_pass}' -Jthreads=${test_threads_count} -Jrampup=${test_rampup_time_sec} -Jruntime=${test_run_time_sec}"
show_command_to_run $cmd
eval $cmd
}
function deallocate_services_in_resource_group
{
local rg=${1}
# Deallocate VMSS's
local scalesets=$(az vmss list -g $rg --query [].name -o tsv)
for scaleset in $scalesets; do
local cmd="az vmss deallocate -g $rg --name $scaleset"
show_command_to_run $cmd
eval $cmd
done
# Deallocate VMs
local cmd="az vm deallocate --ids $(az vm list -g $rg --query [].id -o tsv)"
show_command_to_run $cmd
eval $cmd
# Stopping DBs and redis cache is currently not possible on Azure.
}
function deploy_run_test1_teardown
{
local resource_group=${1}
local location=${2}
local template_url=${3}
local parameters_template_file=${4}
local web_server_type=${5}
local web_vm_sku=${6}
local db_server_type=${7}
local db_vcores=${8}
local db_size_gb=${9}
local file_server_type=${10}
local file_server_disk_count=${11}
local file_server_disk_size=${12}
local redis_cache=${13}
local ssh_pub_key=${14}
local test_threads_count=${15}
local test_rampup_time_sec=${16}
local test_run_time_sec=${17}
local delete_resource_group_flag=${18} # Any non-empty string is considered true
MOODLE_RG_LOCATION=$location
deploy_moodle_with_some_parameters $resource_group $template_url $parameters_template_file $web_server_type $web_vm_sku $db_server_type $db_vcores $db_size_gb $file_server_type $file_server_disk_count $file_server_disk_size $redis_cache "$ssh_pub_key" || return 1
run_simple_test_1_on_resource_group $resource_group $test_threads_count $test_rampup_time_sec $test_run_time_sec 1 || return 1
if [ -n "$delete_resource_group_flag" ]; then
az group delete -g $resource_group -y
else
deallocate_services_in_resource_group $resource_group
fi
}
function check_ssh_agent_and_added_key
{
ssh-add -l
if [ $? != "0" ]; then
echo "No ssh key added to ssh-agent or no ssh-agent is running. Make sure to run ssh-agent (eval `ssh-agent`) and add the correct ssh key (usually just ssh-add will do), so that remote commands execution through ssh doesn't prompt for interactive password."
return 1
fi
}
function run_load_test_example
{
check_ssh_agent_and_added_key || return 1
deploy_run_test1_teardown ltest6 southcentralus https://raw.githubusercontent.com/Azure/Moodle/master/azuredeploy.json azuredeploy.parameters.loadtest.defaults.json apache Standard_DS2_v2 mysql 4 125 nfs 2 128 false "$(cat ~/.ssh/authorized_keys)" 1600 4800 18000
}
function run_load_test_postgres
{
check_ssh_agent_and_added_key || return 1
deploy_run_test1_teardown pgres southcentralus https://raw.githubusercontent.com/Azure/Moodle/master/azuredeploy.json azuredeploy.parameters.loadtest.defaults.json apache Standard_DS2_v2 postgres 16 256 nfs 2 128 false "$(cat ~/.ssh/authorized_keys)" 800 2400 36000
}

Двоичные данные
loadtest/moodle-on-azure-test-course-1.mbz

Двоичный файл не отображается.

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Разница между файлами не показана из-за своего большого размера Загрузить разницу