Skip to content

Commit 435f5f1

Browse files
Read metrics store credentials from Vault
With this commit we allow Rally to use different metrics stores and read the respective credentials from Vault. This change is also integrated into the Vagrant workflow as well as night-rally-admin which can still be used locally. Relates elastic#103
1 parent 2eb1a1e commit 435f5f1

File tree

19 files changed

+317
-111
lines changed

19 files changed

+317
-111
lines changed

Makefile

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,10 @@
11
test:
22
python3 setup.py test
33

4-
install:
4+
install: configure
55
@ ./install.sh
66

7-
.PHONY: test install
7+
configure:
8+
@ ./night_rally/fixtures/ansible/configure.sh
9+
10+
.PHONY: test install configure

README.md

Lines changed: 40 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,9 @@ Night Rally is only tested on Mac OS X and Linux.
1818

1919
1. Ensure that all prerequisites of [Rally](https://github.com/elastic/rally) are properly setup. Hint. It is *not* required to install Rally manually. Just ensure that its prerequisites are installed.
2020
2. Clone this repo: `git clone [email protected]:elastic/night-rally.git`
21-
3. Create a virtualenv with `python3 -m venv .venv` and activate it with `./.venv/bin/activate`
22-
4. Run `make install`
21+
3. [Setup Vault](https://github.com/elastic/infra/blob/master/docs/vault.md)
22+
4. Create a virtualenv with `python3 -m venv .venv` and activate it with `./.venv/bin/activate`
23+
5. Run `make install`
2324

2425
Now you can invoke Night Rally regularly with the startup script `night_rally.sh` e.g. via cron. The script can also self-update if invoked as `night_rally.sh --self-update`.
2526

@@ -131,10 +132,45 @@ To iterate on changes, always remember to re-run `./update_jenkins_night_rally.s
131132
6. `sudo -iu jenkins`
132133
7. Run `./test_nightly.sh`
133134
134-
Results will be sent to the Elastic Cloud cluster `night-rally-tests` (details in LastPass).
135-
136135
To iterate on changes, always remember to re-run `./update_jenkins_night_rally.sh` as user `vagrant`, before re-running tests.
137136
137+
The Vagrant workflow retrieves credentials to the metrics store via Vault so ensure that it is [properly setup](https://github.com/elastic/infra/blob/master/docs/vault.md#github-auth). By default results will be sent to the Elastic Cloud cluster `night-rally-tests` (details in LastPass). In order to write to a different metrics store, you need to:
138+
139+
1. Add credentials to Vault:
140+
141+
1.1 Create a file containing the cluster properties, e.g. in `~/cluster-creds.json`:
142+
143+
```
144+
{
145+
"es_host": "cloud-host-name.eu-central-1.aws.cloud.es.io",
146+
"es_password": "PASSWORD",
147+
"es_username": "USERNAME",
148+
"es_port": "9243",
149+
"cloud_id": "CLOUD_ID_FROM_UI_AT_CLOUD_ELASTIC_CO",
150+
"es_secure": "true"
151+
}
152+
```
153+
1.2 Add the key-value pairs to Vault. Please use `/secret/rally/cloud` as path prefix:
154+
155+
```
156+
vault write /secret/rally/cloud/your-metrics-cluster-name @cluster-creds.json
157+
```
158+
1.3 Check that the data are present
159+
160+
```
161+
vault read /secret/rally/cloud/your-metrics-cluster-name
162+
```
163+
164+
1.4 Delete the cluster properties file
165+
166+
```
167+
rm ~/cluster-creds.json
168+
```
169+
170+
2. `export VAULT_NIGHT_RALLY_METRICS_STORE_CREDENTIAL_PATH=/secret/rally/cloud/your-metrics-cluster-name`
171+
172+
Afterwards you can start the Vagrant boxes.
173+
138174
##### Testing fixtures
139175
140176
You can also simulate the application of fixtures like encryption-at-rest.

night_rally.sh

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,11 @@ while [[ -h $SOURCE ]]; do # resolve $SOURCE until the file is no longer a symli
2424
done
2525
NIGHT_RALLY_HOME="$( cd -P "$( dirname "$SOURCE" )" && pwd )"
2626

27+
# Interactive users are required to be logged in already, others (like Jenkins) will expose VAULT_SECRET_ID env variable.
28+
if [[ -n $VAULT_SECRET_ID && -n $VAULT_ROLE_ID ]]; then
29+
export VAULT_TOKEN=$( curl -s -X POST -H "Content-Type: application/json" -L -d "{\"role_id\":\"$VAULT_ROLE_ID\",\"secret_id\":\"$VAULT_SECRET_ID\"}" $VAULT_ADDR/v1/auth/approle/login | jq -r '.auth.client_token')
30+
fi
31+
RALLY_METRICS_STORE_CREDENTIAL_PATH=${RALLY_METRICS_STORE_CREDENTIAL_PATH:-"/secret/rally/cloud/nightly-rally-metrics"}
2732

2833
ANSIBLE_ALL_TAGS=(encryption-at-rest initialize-data-disk trim drop-caches)
2934
ANSIBLE_SKIP_TAGS=( )

night_rally/admin.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -312,9 +312,9 @@ def positive_number(v):
312312

313313
def main():
314314
parser = arg_parser()
315-
es = client.create_client()
316-
317315
args = parser.parse_args()
316+
317+
es = client.create_client(args.environment)
318318
if args.subcommand == "list":
319319
if args.configuration == "races":
320320
list_races(es, args)

night_rally/client.py

Lines changed: 7 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,25 +1,22 @@
1-
def create_client(configuration_name=None):
1+
def create_client(configuration_name):
22
import configparser
33
import elasticsearch
44
import certifi
55
import pathlib
66

77
def load():
88
config = configparser.ConfigParser(interpolation=configparser.ExtendedInterpolation())
9-
if configuration_name:
10-
# invoked from night-rally
11-
_rally_ini_path = str(pathlib.Path.home()/".rally"/"rally-{}.ini".format(configuration_name))
12-
else:
13-
# invoked from e.g. night-rally-admin, ini files not deployed via Ansible
14-
_rally_ini_path = str(pathlib.PurePath(__file__).parent/"fixtures/ansible/roles/rally-update/templates/rally.ini.j2")
15-
config.read(_rally_ini_path)
9+
config_file = pathlib.Path.home()/".rally"/"rally-{}.ini".format(configuration_name)
10+
if not config_file.exists():
11+
raise IOError("Config file [{}] is missing".format(config_file))
12+
config.read(str(config_file))
1613
return config
1714

1815
complete_cfg = load()
1916
cfg = complete_cfg["reporting"]
20-
if cfg["datastore.secure"] == "True":
17+
if cfg["datastore.secure"].lower() == "true":
2118
secure = True
22-
elif cfg["datastore.secure"] == "False":
19+
elif cfg["datastore.secure"].lower() == "false":
2320
secure = False
2421
else:
2522
raise ValueError("Setting [datastore.secure] is neither [True] nor [False] but [%s]" % cfg["datastore.secure"])

night_rally/fixtures/ansible/README.md

Lines changed: 0 additions & 24 deletions
This file was deleted.

night_rally/fixtures/ansible/Vagrantfile

Lines changed: 18 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ end
4242

4343
def install_jenkins_user
4444
<<~EOF
45+
set +x
4546
groupadd -g 1010 jenkins
4647
useradd -u 1010 -g 1010 -s /bin/bash -m -k /etc/skel -d /var/lib/jenkins jenkins
4748
mkdir /var/lib/jenkins/.ssh
@@ -102,7 +103,6 @@ def install_night_rally_test_script(base_ip, target_node_ip_addresses)
102103
export FIXTURES=${FIXTURES:-}
103104
export COORDINATING_NODES=#{base_ip}
104105
export TARGET_HOSTS="#{target_node_ip_addresses.join(',')}"
105-
export IN_VAGRANT=YES
106106
export TEST_MODE=YES
107107
EOF2
108108
@@ -146,6 +146,17 @@ def symlink_java_8
146146
"ln -s /usr/lib/jvm/java-8-openjdk-amd64 /var/lib/jenkins/.java/java8"
147147
end
148148

149+
def pass_additional_jenkins_env_vars
150+
<<~EOF
151+
set +x
152+
cat >>/var/lib/jenkins/.profile <<EOF2
153+
export VAULT_ADDR=https://secrets.elastic.co:8200
154+
export RALLY_METRICS_STORE_CREDENTIAL_PATH=${RALLY_METRICS_STORE_CREDENTIAL_PATH:-/secret/rally/cloud/vagrant-test-rally-metrics}
155+
export IN_VAGRANT=YES
156+
EOF2
157+
EOF
158+
end
159+
149160
Vagrant.configure(2) do |config|
150161
use_cachier = false
151162
if Vagrant.has_plugin?('vagrant-cachier') and not ENV['VAGRANT_NO_CACHIER']
@@ -183,12 +194,16 @@ Vagrant.configure(2) do |config|
183194
file_to_disk = File.realpath("vagrantdisk").to_s + "/#{node[:hostname]}_disk.vdi"
184195
vbox.customize ['createhd', '--filename', file_to_disk, '--size', 4*1024, '--format', 'VDI'] # Size is in MiB
185196
vbox.customize ['storageattach', :id, '--storagectl', 'IDE Controller', '--port', 1, '--device', 0, '--type', 'hdd', '--medium', file_to_disk]
197+
198+
if node[:hostname] == "coordinator"
199+
override_config.vm.synced_folder "#{Dir.home}/", "/home/vagrant/", type: "rsync", rsync__args: ["-r", "--include=.vault-token", "--exclude=*"]
200+
end
186201
end
187202

188203
node_config.ssh.forward_agent = true
189-
190204
node_config.vm.provision "shell", inline: tweak_es_sysctl
191205
node_config.vm.provision "shell", inline: install_jenkins_user
206+
node_config.vm.provision "shell", inline: pass_additional_jenkins_env_vars, env: {"RALLY_METRICS_STORE_CREDENTIAL_PATH" => ENV["VAULT_NIGHT_RALLY_METRICS_STORE_CREDENTIAL_PATH"]}
192207
node_config.vm.provision "shell", inline: install_rally_user
193208
node_config.vm.provision "shell", inline: rally_sudoers
194209
node_config.vm.provision "shell", inline: install_rally_source
@@ -206,7 +221,7 @@ Vagrant.configure(2) do |config|
206221
# required because installing night_rally needs write access to the `.egg` directory
207222
if node == nodes.first
208223
node_config.vm.provision "shell", inline: <<-EOF
209-
echo 'sudo rsync -r -o -g --chown=jenkins:jenkins --exclude ".vagrant" --exclude "vagrantdisk" /night_rally /var/lib/jenkins/' \
224+
echo 'sudo rsync -r -o -g --chown=jenkins:jenkins --exclude ".vagrant" --exclude "vagrantdisk" /night_rally /home/vagrant/.vault-token /var/lib/jenkins/' \
210225
>/home/vagrant/update_jenkins_night_rally.sh
211226
chmod +x update_jenkins_night_rally.sh
212227
./update_jenkins_night_rally.sh

night_rally/fixtures/ansible/ansible.cfg

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ display_skipped_hosts = false
44
host_key_checking = false
55
inventory = inventory/local
66
library = library
7+
lookup_plugins = plugins/lookup_plugins
78
nocows = 1
89
retry_files_save_path = ~/.ansible
910
roles_path = roles
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
#!/usr/bin/env bash
2+
3+
set -e
4+
5+
SOURCE="${BASH_SOURCE[0]}"
6+
while [[ -h $SOURCE ]]; do # resolve $SOURCE until the file is no longer a symlink
7+
DIR="$( cd -P "$( dirname "$SOURCE" )" && pwd )"
8+
SOURCE="$(readlink "$SOURCE")"
9+
[[ ${SOURCE} != /* ]] && SOURCE="$DIR/$SOURCE" # if $SOURCE was a relative symlink, we need to resolve it relative to the path where the symlink file was located
10+
done
11+
SCRIPT_HOME="$( cd -P "$( dirname "$SOURCE" )" && pwd )"
12+
13+
cd ${SCRIPT_HOME}
14+
15+
export RALLY_METRICS_STORE_CREDENTIAL_PATH=${RALLY_METRICS_STORE_CREDENTIAL_PATH:-"/secret/rally/cloud/nightly-rally-metrics"}
16+
# attempt to read so we can determine early on whether the user is logged in
17+
set +e
18+
vault read ${RALLY_METRICS_STORE_CREDENTIAL_PATH} > /dev/null 2>&1
19+
exit_code=$?
20+
set -e
21+
if [[ ${exit_code} -ne 0 ]]; then
22+
echo "Failed to read from ${RALLY_METRICS_STORE_CREDENTIAL_PATH}. Please log in to Vault."
23+
exit 1
24+
fi
25+
26+
virtualenv --python=python2.7 .venv
27+
.venv/bin/pip install -q -r requirements.txt
28+
source ./.venv/bin/activate
29+
# Workaround for https://github.com/ansible/ansible/issues/31869 which is
30+
# basically a Python deficiency (see
31+
# http://sealiesoftware.com/blog/archive/2017/6/5/Objective-C_and_fork_in_macOS_1013.html
32+
# for details).
33+
export OBJC_DISABLE_INITIALIZE_FORK_SAFETY=YES
34+
35+
ansible-playbook --connection=local playbooks/configure-rally.yml --extra-vars="rally_environment=nightly local_setup=true"
36+
ansible-playbook --connection=local playbooks/configure-rally.yml --extra-vars="rally_environment=release local_setup=true"
37+
# TODO: Remove this after the cutover period.
38+
ansible-playbook --connection=local playbooks/configure-rally.yml --extra-vars="rally_environment=release-new local_setup=true"
39+
ansible-playbook --connection=local playbooks/configure-rally.yml --extra-vars="rally_environment=nightly-new local_setup=true"
40+
unset OBJC_DISABLE_INITIALIZE_FORK_SAFETY
41+
deactivate
42+
cd - > /dev/null
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
---
2+
3+
- name: Configures Rally locally
4+
# ==============================
5+
hosts: localhost
6+
connection: local
7+
gather_facts: false
8+
roles:
9+
- { role: rally-configure, tags: rally-configure }

night_rally/fixtures/ansible/playbooks/update-rally.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
hosts: coordinating-nodes, target-hosts
88
gather_facts: true
99
roles:
10+
- { role: rally-configure, tags: rally-configure }
1011
- { role: rally-update, tags: rally-update }
1112
serial:
1213
- 1

0 commit comments

Comments
 (0)