Skip to content

Commit bb2d934

Browse files
authored
Merge pull request #27 from f5devcentral/prettify
Prettify
2 parents ebeb731 + e1fa26d commit bb2d934

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

43 files changed

+2016
-479
lines changed

labapp/app/app.py

+120-80
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
import re
66
import json
77
import requests
8+
import base64
89
import urllib
910
from flask import Flask, render_template, jsonify, request, redirect, make_response, flash, url_for
1011
from flask_caching import Cache
@@ -19,10 +20,13 @@
1920
if os.getenv('UDF', None):
2021
app.config['ce_info'] = get_ce_info()
2122
app.config['UDF'] = True
23+
app.config['SESSION_COOKIE_SECURE'] = True
2224
app.config['base_url'] = "mcn-lab.f5demos.com"
2325
app.config['CACHE_TYPE'] = 'SimpleCache'
2426
cache = Cache(app)
2527
app.secret_key = "blahblahblah"
28+
data_cookie = "mcnp-ac-data"
29+
cookie_age = 86400
2630

2731
session = get_runner_session()
2832
session.headers.update({"User-Agent": "MCN-Lab-Runner/1.0"})
@@ -47,42 +51,104 @@ def validate_eph_ns(input_name):
4751

4852
def get_eph_ns() -> str:
4953
"""check if ephemeral namespace is set"""
50-
this_eph_ns = request.cookies.get('eph_ns', None)
51-
return this_eph_ns
54+
try:
55+
cookie_b64 = request.cookies.get(data_cookie, None)
56+
if cookie_b64:
57+
return get_cookie_prop(cookie_b64, 'eph_ns')
58+
except Exception:
59+
print("Error getting ephemeral NS")
60+
return None
61+
62+
def get_site() -> str:
63+
"""check if ephemeral namespace is set"""
64+
if app.config['ce_info']:
65+
return app.config['ce_info'].get("site_name", None)
66+
return None
67+
68+
def update_cookie_prop(cookie_b64, prop, value):
69+
"""Update a property in a base64 encoded JSON cookie."""
70+
try:
71+
json_bytes = base64.b64decode(cookie_b64)
72+
json_str = json_bytes.decode('utf-8')
73+
cookie_data = json.loads(json_str)
74+
if not isinstance(cookie_data, dict):
75+
raise ValueError("Cookie data is not a dictionary.")
76+
cookie_data[prop] = value
77+
updated = json.dumps(cookie_data)
78+
base64_bytes = base64.b64encode(updated.encode('utf-8'))
79+
return base64_bytes.decode('utf-8')
80+
except json.JSONDecodeError:
81+
print("Error decoding JSON from cookie.")
82+
"""TBD: this is not what we want."""
83+
return encode_data({})
84+
except Exception as e:
85+
print(f"An error occurred: {e}")
86+
return encode_data({})
87+
88+
def get_cookie_prop(cookie_b64, prop):
89+
"""get a cookie prop"""
90+
try:
91+
json_bytes = base64.b64decode(cookie_b64)
92+
json_str = json_bytes.decode('utf-8')
93+
c_dict = json.loads(json_str)
94+
return c_dict[prop]
95+
except json.JSONDecodeError:
96+
print("Error decoding cookie data")
97+
return None
98+
99+
def encode_data(data):
100+
"""Encode dictionary to Base64-encoded JSON."""
101+
json_str = json.dumps(data)
102+
base64_bytes = base64.b64encode(json_str.encode('utf-8'))
103+
return base64_bytes.decode('utf-8')
52104

105+
def decode_data(encoded_data):
106+
"""Decode Base64-encoded JSON to dictionary."""
107+
json_bytes = base64.b64decode(encoded_data)
108+
json_str = json_bytes.decode('utf-8')
109+
return json.loads(json_str)
110+
53111
@app.errorhandler(404)
54112
@app.errorhandler(500)
55113
def return_err(err):
56114
"""common error handler"""
57-
img = {
58-
404: "/static/404.png",
59-
500: "/static/500.png"
60-
}
61-
return render_template("error.html", err_img=img[err.code])
115+
return render_template("error.html", code=err.code)
116+
117+
@app.route('/cookie')
118+
def cookie_err():
119+
"""cookie error"""
120+
return render_template("cookie.html")
62121

63122
@app.after_request
64123
def cache_control(response):
65124
"""cache control"""
66125
if request.path.startswith("/static/") and request.path.endswith(".png"):
67126
response.headers['Cache-Control'] = 'public, max-age=3600'
68127
return response
128+
129+
@app.before_request
130+
def ensure_cookie():
131+
"""Ensure that the cookie is present, otherwise redirect to the cookie page."""
132+
if not request.path.startswith('/static'):
133+
if (request.path not in ['/', '/cookie']) and (data_cookie not in request.cookies):
134+
return redirect('/cookie')
69135

70136
@app.route('/')
71137
def index():
72138
"""index page"""
73-
html = render_md("markdown/welcome.md")
74-
return render_template('standard.html',
75-
title="MCN Practical: Overview",
76-
content=html
139+
html = render_template('welcome.html',
140+
title="MCN Practical: Welcome"
77141
)
142+
response = make_response(html)
143+
if data_cookie not in request.cookies:
144+
response.set_cookie(data_cookie, encode_data({}), max_age=cookie_age)
145+
return response
78146

79147
@app.route('/overview')
80-
def arch():
81-
"""arch page"""
82-
html = render_md("markdown/overview.md")
83-
return render_template('standard.html',
84-
title="MCN Practical: Architecture",
85-
content=html
148+
def overview():
149+
"""overview page"""
150+
return render_template('overview.html',
151+
title="MCN Practical: Overview"
86152
)
87153

88154
@app.route('/setup', methods=['GET', 'POST'])
@@ -97,92 +163,58 @@ def setup():
97163
flash("Invalid ephemeral namespace.", "danger")
98164
return redirect(url_for('setup'))
99165
response = make_response(redirect('/setup'))
100-
response.set_cookie('eph_ns', this_eph_ns, max_age=60*60*24)
166+
cookie_b64 = request.cookies.get('mcnp-ac-data', encode_data({}))
167+
cookie_data = update_cookie_prop(cookie_b64, 'eph_ns', this_eph_ns)
168+
response.set_cookie(data_cookie, cookie_data)
101169
flash('Ephemeral namespace successfully set.', "success")
102170
return response
103171
if action == 'clear':
104172
response = make_response(redirect('/setup'))
105-
response.set_cookie('eph_ns', '', expires=0)
173+
cookie_b64 = request.cookies.get('mcnp-ac-data', encode_data({}))
174+
cookie_data = update_cookie_prop(cookie_b64, 'eph_ns', None)
175+
response.set_cookie(data_cookie, cookie_data)
106176
flash("Ephemeral namespace cleared.", "info")
107177
return response
108-
html = render_md("markdown/setup.md")
109178
return render_template('setup.html',
110179
title="MCN Practical: Setup",
111-
content=html,
112180
ns=ns
113181
)
114182

115-
@app.route('/_ce_status')
116-
@cache.cached(timeout=30)
117-
def ce_state():
118-
"""get ce state (internal route)"""
119-
data = get_ce_state(app.config['ce_info'])
120-
return data
121-
122183
@app.route('/loadbalancing')
123184
def lb():
124185
"""lb page"""
125186
ns = get_eph_ns()
126-
html = render_md("markdown/lb.md")
127-
return render_template('exercise_standard.html',
187+
site = get_site()
188+
return render_template('loadbalancing.html',
128189
title="MCN Practical: LB",
129-
content=html,
190+
site=site,
130191
ns=ns
131192
)
132193

133194
@app.route('/route')
134195
def path():
135196
"""routing page"""
136197
ns = get_eph_ns()
137-
html = render_md("markdown/route.md")
138-
return render_template('exercise_standard.html',
198+
return render_template('route.html',
139199
title="MCN Practical: HTTP Routing",
140-
content=html,
141-
ns=ns,
142-
200+
ns=ns
143201
)
144202

145203
@app.route('/manipulation')
146204
def header():
147205
"""manipulation page"""
148206
ns = get_eph_ns()
149-
html = render_md("markdown/manipulation.md")
150-
return render_template('exercise_standard.html',
207+
return render_template('manipulation.html',
151208
title="MCN Practical: Manipulation",
152-
content=html,
153209
ns=ns
154210
)
155211

156212
@app.route('/portability')
157213
def port():
158214
"""portability page"""
159215
ns = get_eph_ns()
160-
html = render_md("markdown/portability.md")
161-
return render_template('exercise_standard.html',
216+
return render_template('portability.html',
162217
title="MCN Practical: Portability",
163-
content=html,
164-
ns=ns
165-
)
166-
167-
@app.route('/vnet')
168-
def vnet():
169-
"""vnet page"""
170-
ns = get_eph_ns()
171-
html = render_md("markdown/reference.md")
172-
return render_template('coming-soon.html',
173-
title="MCN Practical: Reference",
174-
content=html,
175-
ns=ns
176-
)
177-
178-
@app.route('/netpolicy')
179-
def netp():
180-
"""netpolicy page"""
181-
ns = get_eph_ns()
182-
html = render_md("markdown/reference.md")
183-
return render_template('coming-soon.html',
184-
title="MCN Practical: Reference",
185-
content=html,
186218
ns=ns
187219
)
188220

@@ -200,14 +232,12 @@ def ref():
200232
@app.route('/score')
201233
def score():
202234
"""scoreboard page"""
203-
ns = get_eph_ns()
204-
score_cookie = request.cookies.get('score', '%7B%7D')
205-
print(score_cookie)
206235
try:
207-
decoded_cookie = urllib.parse.unquote(score_cookie)
208-
enc_score = json.loads(decoded_cookie)
209-
this_score = {urllib.parse.unquote(k): v for k, v in enc_score.items()}
210-
except json.JSONDecodeError:
236+
cookie_b64 = request.cookies.get(data_cookie)
237+
this_score = get_cookie_prop(cookie_b64, 'score')
238+
"""raise a LabException"""
239+
except Exception:
240+
print("Error getting score")
211241
this_score = {}
212242
try:
213243
p_score = score_get_results(this_score)
@@ -218,19 +248,29 @@ def score():
218248
port_table = score_build_table(p_score, 'port', 'Portability')
219249
except LabException as e:
220250
print(f"Couldn't build score table: {e}")
221-
response = make_response(render_template('score.html',
251+
return render_template('score.html',
222252
title="MCN Practical: Scoreboard",
223253
over_table=over_table,
224254
lb_table=lb_table,
225255
route_table=route_table,
226256
manip_table=manip_table,
227257
port_table=port_table,
228-
ns=ns
229-
))
230-
response.headers['Cache-Control'] = 'no-cache, no-store, must-revalidate'
231-
response.headers['Pragma'] = 'no-cache'
232-
response.headers['Expires'] = '0'
233-
return response
258+
)
259+
260+
@app.route('/test')
261+
def test():
262+
"""test page"""
263+
ns = get_eph_ns()
264+
return render_template('test.html',
265+
title="MCN Practical: Test",
266+
ns=ns
267+
)
268+
269+
@app.route('/_ce_status')
270+
def ce_state():
271+
"""get ce state (internal route)"""
272+
data = get_ce_state(app.config['ce_info'])
273+
return data
234274

235275
@app.route('/_test1')
236276
def ex_test():
@@ -359,11 +399,12 @@ def manip2():
359399
"""Second Manip Test"""
360400
try:
361401
ns = get_eph_ns()
402+
site = get_site()
362403
if not ns:
363404
raise LabException("Ephemeral NS not set")
364405
base_url = app.config['base_url']
365406
url = f"https://{ns}.{base_url}/"
366-
t_headers = { "x-mcn-namespace": ns, "x-mcn-src-site": app.config["ce_info"]["site_name"]}
407+
t_headers = { "x-mcn-namespace": ns, "x-mcn-src-site": site}
367408
r_data = cloudapp_req_headers(session, url, 7, t_headers)
368409
return jsonify(status='success', data=r_data)
369410
except (LabException, ValueError) as e:
@@ -415,7 +456,6 @@ def port2():
415456
"""Friend test"""
416457
try:
417458
data = request.get_json()
418-
print(data)
419459
eph_ns = data['userInput']
420460
url = f"https://{eph_ns}.{app.config['base_url']}/"
421461
data = cloudapp_fetch(session, url, 7, 'info', {"method": "GET", "path": "/"})

labapp/app/score.py

+1-4
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@
4040
"href": "/route",
4141
"result": "none"
4242
},
43-
"/_manip1:": {
43+
"/_manip1": {
4444
"name": "Path Rewrite",
4545
"key": "manip",
4646
"href": "/manipulation",
@@ -86,8 +86,6 @@ def score_get_results(cookie_results):
8686
for test_path, result in cookie_results.items():
8787
if test_path in score_schema:
8888
this_score[test_path]['result'] = result
89-
print(this_score)
90-
print(score_schema)
9189
return this_score
9290

9391
def score_sort(scores, key):
@@ -100,7 +98,6 @@ def score_build_table(scores, section, name):
10098
section_scores = score_sort(scores, section)
10199
rows_html = ""
102100
for key, score in section_scores.items():
103-
print(score['result'])
104101
r_icon = result_map[score['result']]
105102
section_html = f"""
106103
<tr>

labapp/app/static/arch.png

-1.14 MB
Binary file not shown.

0 commit comments

Comments
 (0)