Skip to content

Commit 93c9edd

Browse files
authored
Add --url and --api-auth-token options to lnt create (#195)
Replace --hostname/--hostsuffix with a single --url option that sets zorgURL directly, and add --api-auth-token to write the API token into the generated config. This eliminates the need for callers to manually append settings to lnt.cfg after creation. Also simplify the generated WSGI template to not suggest that it should be run manually, which is incorrect (use `lnt runserver` instead). Fixes #180
1 parent 8f8dad7 commit 93c9edd

File tree

5 files changed

+104
-35
lines changed

5 files changed

+104
-35
lines changed

docker/docker-entrypoint.sh

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -13,12 +13,8 @@ if [ ! -e /var/lib/lnt/instance/lnt.cfg ]; then
1313
--wsgi lnt_wsgi.py \
1414
--tmp-dir /tmp/lnt \
1515
--db-dir "${DB_PATH}" \
16-
--default-db "${DB_NAME}"
17-
if [[ "${token}" == *"'"* ]]; then
18-
echo "Invalid API auth token containing single quote ('): that character is used as a delimiter in the config file"
19-
exit 1
20-
fi
21-
echo "api_auth_token = '${token}'" >> /var/lib/lnt/instance/lnt.cfg
16+
--default-db "${DB_NAME}" \
17+
--api-auth-token "${token}"
2218
fi
2319

2420
# Run the server under gunicorn.

docs/tools.rst

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -110,6 +110,10 @@ The following tools are used to interact with an LNT server:
110110
The default server will have a sqlite3 database named *default*. You can
111111
specify to use PostgreSQL using ``--db-dir postgresql://user@hostname``.
112112

113+
Use ``--url`` to set the externally-visible base URL of the server (used in
114+
email reports). Use ``--api-auth-token`` to set the REST API authentication
115+
token.
116+
113117
``lnt import <instance path> <file>+``
114118
Import an LNT data file into a database. You can use ``--database`` to
115119
select the database to write to. Note that by default this will also

lnt/lnttool/create.py

Lines changed: 14 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
import click
2-
import platform
32

43

54
kConfigVersion = (0, 1, 0)
@@ -34,7 +33,7 @@
3433
secret_key = %(secret_key)r
3534
3635
# REST API authentication
37-
# api_auth_token = 'secret'
36+
%(api_auth_token_line)s
3837
3938
# The list of available databases, and their properties. At a minimum, there
4039
# should be a 'default' entry for the default database.
@@ -61,17 +60,9 @@
6160
"""
6261

6362
kWSGITemplate = """\
64-
#!%(python_executable)s
65-
# -*- Python -*-
66-
6763
import lnt.server.ui.app
6864
69-
application = lnt.server.ui.app.App.create_standalone(
70-
%(cfg_path)r)
71-
72-
if __name__ == "__main__":
73-
import werkzeug
74-
werkzeug.run_simple('%(hostname)s', 8000, application)
65+
application = lnt.server.ui.app.App.create_standalone(%(cfg_path)r)
7566
"""
7667

7768

@@ -93,14 +84,14 @@
9384
help="name for the default db")
9485
@click.option("--secret-key", default=None,
9586
help="secret key to use for this installation")
96-
@click.option("--hostname", default=platform.uname()[1], show_default=True,
97-
help="host name of the server")
98-
@click.option("--hostsuffix", default="perf", show_default=True,
99-
help="suffix at which WSGI app lives")
87+
@click.option("--url", default="http://localhost", show_default=True,
88+
help="base URL of the server, used in email reports")
89+
@click.option("--api-auth-token", default=None,
90+
help="authentication token for the REST API")
10091
@click.option("--show-sql", is_flag=True,
10192
help="show SQL statements executed during construction")
10293
def action_create(instance_path, name, config, wsgi, tmp_dir, db_dir,
103-
profile_dir, default_db, secret_key, hostname, hostsuffix,
94+
profile_dir, default_db, secret_key, url, api_auth_token,
10495
show_sql):
10596
"""create an LLVM nightly test installation
10697
@@ -116,7 +107,6 @@ def action_create(instance_path, name, config, wsgi, tmp_dir, db_dir,
116107
import logging
117108
import os
118109
import random
119-
import sys
120110

121111
init_logger(logging.INFO if show_sql else logging.WARNING,
122112
show_sql=show_sql)
@@ -125,9 +115,8 @@ def action_create(instance_path, name, config, wsgi, tmp_dir, db_dir,
125115
if os.path.exists(basepath):
126116
raise SystemExit("error: invalid path: %r already exists" % basepath)
127117

128-
hosturl = "http://%s/%s" % (hostname, hostsuffix)
118+
hosturl = url
129119

130-
python_executable = sys.executable
131120
cfg_path = os.path.join(basepath, config)
132121
tmp_path = os.path.join(basepath, tmp_dir)
133122
wsgi_path = os.path.join(basepath, wsgi)
@@ -139,6 +128,11 @@ def action_create(instance_path, name, config, wsgi, tmp_dir, db_dir,
139128
).hexdigest()
140129
)
141130

131+
if api_auth_token is not None:
132+
api_auth_token_line = "api_auth_token = %r" % api_auth_token
133+
else:
134+
api_auth_token_line = "# api_auth_token = 'secret'"
135+
142136
os.mkdir(instance_path)
143137
os.mkdir(tmp_path)
144138
os.mkdir(schemas_path)
@@ -172,7 +166,7 @@ def action_create(instance_path, name, config, wsgi, tmp_dir, db_dir,
172166
print(' host URL : %s' % hosturl)
173167
print()
174168
print('You can execute:')
175-
print(' %s' % wsgi_path)
169+
print(' lnt runserver %s' % basepath)
176170
print('to test your installation with the builtin server.')
177171
print()
178172
print('For production use configure this application to run with any')

tests/lnttool/create.shtest

Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
# Test 'lnt create' end-to-end.
2+
3+
###############################################################################
4+
# Default creation: verify the generated config and instance file hierarchy
5+
###############################################################################
6+
# RUN: rm -rf %t.instance
7+
# RUN: lnt create %t.instance > %t.create-output
8+
9+
# -- Config file contains all expected fields with default values
10+
# RUN: filecheck --check-prefix CHECK-CFG %s < %t.instance/lnt.cfg
11+
12+
# CHECK-CFG: config_version = (0, 1, 0)
13+
# CHECK-CFG: name = 'LNT'
14+
# CHECK-CFG: zorgURL = 'http://localhost'
15+
# CHECK-CFG: tmp_dir = 'lnt_tmp'
16+
# CHECK-CFG: db_dir = 'data'
17+
# CHECK-CFG: profile_dir = 'data/profiles'
18+
# CHECK-CFG: secret_key =
19+
# CHECK-CFG: # api_auth_token = 'secret'
20+
# CHECK-CFG: databases = {
21+
# CHECK-CFG-NEXT: 'default' : { 'path' : 'lnt.db' },
22+
# CHECK-CFG: nt_emailer = {
23+
24+
# -- Directory structure is created
25+
# RUN: test -d %t.instance/lnt_tmp
26+
# RUN: test -d %t.instance/data
27+
# RUN: test -d %t.instance/schemas
28+
# RUN: test -f %t.instance/data/lnt.db
29+
30+
###############################################################################
31+
# Make sure that custom options all take effect
32+
###############################################################################
33+
# RUN: rm -rf %t.custom
34+
# RUN: lnt create %t.custom \
35+
# RUN: --name "My LNT" \
36+
# RUN: --url https://example.com/lnt \
37+
# RUN: --api-auth-token mytoken \
38+
# RUN: --secret-key deadbeef \
39+
# RUN: --default-db custom.db \
40+
# RUN: --db-dir databases \
41+
# RUN: --tmp-dir mytmp \
42+
# RUN: --profile-dir my/profiles
43+
# RUN: filecheck --check-prefix CHECK-CUSTOM %s < %t.custom/lnt.cfg
44+
45+
# CHECK-CUSTOM: name = 'My LNT'
46+
# CHECK-CUSTOM: zorgURL = 'https://example.com/lnt'
47+
# CHECK-CUSTOM: tmp_dir = 'mytmp'
48+
# CHECK-CUSTOM: db_dir = 'databases'
49+
# CHECK-CUSTOM: profile_dir = 'my/profiles'
50+
# CHECK-CUSTOM: secret_key = 'deadbeef'
51+
# CHECK-CUSTOM: api_auth_token = 'mytoken'
52+
# CHECK-CUSTOM: 'default' : { 'path' : 'custom.db' },
53+
54+
# RUN: test -d %t.custom/mytmp
55+
# RUN: test -d %t.custom/databases
56+
# RUN: test -f %t.custom/databases/custom.db
57+
58+
###############################################################################
59+
# Error: creating into an existing path fails.
60+
###############################################################################
61+
# RUN: rm -rf %t.exists && mkdir %t.exists
62+
# RUN: not lnt create %t.exists 2> %t.exists-err
63+
# RUN: filecheck --check-prefix CHECK-EXISTS %s < %t.exists-err
64+
65+
# CHECK-EXISTS: error: invalid path: {{.*}} already exists
66+
67+
###############################################################################
68+
# The generated instance can be loaded by lnt runserver (smoke test: just
69+
# verify that 'lnt import' can talk to the instance, which requires loading
70+
# the config and database).
71+
###############################################################################
72+
# RUN: lnt import %t.instance %{shared_inputs}/sample-a-small.plist --show-sample-count > %t.import-output
73+
# RUN: filecheck --check-prefix CHECK-IMPORT %s < %t.import-output
74+
75+
# CHECK-IMPORT: Import succeeded.

tests/utils/with_temporary_instance.py

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,13 @@ def main():
4646
db_name = os.environ['LNT_TEST_DB_NAME']
4747

4848
# 1. Create the LNT instance.
49-
subprocess.check_call(['lnt', 'create', dest_dir, '--db-dir', db_uri, '--default-db', db_name])
49+
subprocess.check_call([
50+
'lnt', 'create', dest_dir,
51+
'--db-dir', db_uri,
52+
'--default-db', db_name,
53+
'--api-auth-token', 'test_token',
54+
'--url', 'http://localhost/perf',
55+
])
5056

5157
# 2. Symlink schema YAML files into the instance.
5258
script_dir = os.path.dirname(os.path.abspath(__file__))
@@ -58,13 +64,7 @@ def main():
5864
os.path.join(schemas_dst, schema),
5965
)
6066

61-
# 3. Append test configuration to lnt.cfg.
62-
cfg_path = os.path.join(dest_dir, 'lnt.cfg')
63-
with open(cfg_path, 'a') as f:
64-
f.write("\napi_auth_token = \"test_token\"\n")
65-
f.write("zorgURL = 'http://localhost/perf'\n")
66-
67-
# 4. Import JSON report files from each DATA_DIR (or individual file).
67+
# 3. Import JSON report files from each DATA_DIR (or individual file).
6868
for data_path in data_dirs:
6969
if os.path.isdir(data_path):
7070
json_files = sorted(glob.glob(os.path.join(data_path, '*.json')))
@@ -76,7 +76,7 @@ def main():
7676
suite = data.get('schema', 'nts')
7777
subprocess.check_call(['lnt', 'import', '-s', suite, '--merge', 'append', dest_dir, json_file])
7878

79-
# 5. Exec the wrapped command.
79+
# 4. Exec the wrapped command.
8080
os.execvp(command[0], command)
8181

8282

0 commit comments

Comments
 (0)