initial
This commit is contained in:
parent
68913cedd8
commit
97b7a2ba47
|
@ -1,2 +1,5 @@
|
||||||
.vscode
|
.vscode
|
||||||
venv
|
venv
|
||||||
|
__pycache__
|
||||||
|
Dev-kubeconfig.yaml
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,18 @@
|
||||||
|
FROM python:3.10-alpine
|
||||||
|
|
||||||
|
RUN <<EOF
|
||||||
|
apk update
|
||||||
|
apk add --update curl
|
||||||
|
EOF
|
||||||
|
RUN pip3 install flask randomname requests
|
||||||
|
# COPY /python /home/python
|
||||||
|
WORKDIR /home/python
|
||||||
|
|
||||||
|
# RUN python3 -m venv /home/python/venv
|
||||||
|
# RUN source /home/python/venv/bin/activate && pip3 install flask edgegrid-python randomname names
|
||||||
|
|
||||||
|
ENTRYPOINT ["python3"]
|
||||||
|
CMD ["app.py"]
|
||||||
|
|
||||||
|
# CMD ["/bin/sh"]
|
||||||
|
# CMD ["/home/python/venv/bin/python" "app.py"]
|
|
@ -0,0 +1,337 @@
|
||||||
|
from flask import Flask, request, make_response, abort, jsonify, render_template, send_file
|
||||||
|
from akamai.edgegrid import EdgeGridAuth
|
||||||
|
from urllib.parse import urljoin
|
||||||
|
from datetime import datetime, timedelta
|
||||||
|
import requests
|
||||||
|
import time
|
||||||
|
import subprocess
|
||||||
|
import logging
|
||||||
|
import re
|
||||||
|
import json
|
||||||
|
import akamai_functions, docebo_functions, coder_functions
|
||||||
|
from threading import Thread
|
||||||
|
import randomname
|
||||||
|
from io import StringIO
|
||||||
|
import os
|
||||||
|
|
||||||
|
app = Flask(__name__)
|
||||||
|
app.logger.setLevel(logging.DEBUG)
|
||||||
|
|
||||||
|
# How can we update coder admin_token??? What is the maximum expiration days?
|
||||||
|
# coder server --max-token-lifetime. Default 2540400 hours = 290 days
|
||||||
|
# The maximum lifetime duration users can specify when creating an API token.
|
||||||
|
# coder tokens create --lifetime. Default 720 hours = 30 days
|
||||||
|
# Specify a duration for the lifetime of the token.
|
||||||
|
# Create token API key - curl -X POST http://coder-server:8080/api/v2/users/{user}/keys/tokens
|
||||||
|
# {
|
||||||
|
# "lifetime": 0,
|
||||||
|
# "scope": "all",
|
||||||
|
# "token_name": "string"
|
||||||
|
# }
|
||||||
|
|
||||||
|
admin_token = 'gNmzL1TLeN-gXfs7q10uWPINqtlpt02Pj'
|
||||||
|
template_id = 'a5577a86-e700-41be-997b-6001d78061d4'
|
||||||
|
user_email = 'learn@akamai.com'
|
||||||
|
user_pwd = 'Qodnwk=$s8'
|
||||||
|
|
||||||
|
token_header = {'Coder-Session-Token': admin_token,
|
||||||
|
'Accept': 'application/json'}
|
||||||
|
token_param = {'email': user_email, 'password': user_pwd}
|
||||||
|
|
||||||
|
# unused hours of workspace
|
||||||
|
unused_hours = 2
|
||||||
|
|
||||||
|
# workspace ttl ms
|
||||||
|
ttl = 86400000 # 24 hours
|
||||||
|
|
||||||
|
###################################################
|
||||||
|
# Control Center API functions start #
|
||||||
|
###################################################
|
||||||
|
|
||||||
|
@app.route('/flask/cc_download')
|
||||||
|
def cc_download():
|
||||||
|
firstName = randomname.get_name()
|
||||||
|
lastName = randomname.get_name()
|
||||||
|
app.logger.debug('firstName= %s, lastName= %s', firstName, lastName)
|
||||||
|
|
||||||
|
app.logger.debug('get_users starts')
|
||||||
|
users = akamai_functions.get_all_users()
|
||||||
|
app.logger.debug('get_users ends')
|
||||||
|
|
||||||
|
app.logger.debug('select_user starts')
|
||||||
|
user = akamai_functions.select_user(users, unused_hours, firstName, lastName)
|
||||||
|
uiIdentityId = user['uiIdentityId']
|
||||||
|
app.logger.debug('select_user ends. uiIdentityId= %s', uiIdentityId)
|
||||||
|
|
||||||
|
app.logger.debug('reset_user_pwd starts')
|
||||||
|
pwd = akamai_functions.reset_user_pwd(uiIdentityId)
|
||||||
|
app.logger.debug('reset_user_pwd ends')
|
||||||
|
|
||||||
|
authorizedUser = user['uiUserName']
|
||||||
|
app.logger.debug(f'authorizedUser= {authorizedUser}')
|
||||||
|
credential = akamai_functions.find_credential(authorizedUser, '/home/akamai/dev/learnakamai/json/api_clients.json')
|
||||||
|
if credential is not None:
|
||||||
|
new_credential = akamai_functions.create_credential(credential)
|
||||||
|
if new_credential is not None:
|
||||||
|
credential = new_credential
|
||||||
|
else:
|
||||||
|
abort(500, description="cannot create new credential")
|
||||||
|
else:
|
||||||
|
abort(500, description="cannot find credential")
|
||||||
|
|
||||||
|
email = user['email']
|
||||||
|
if email != None and pwd != None:
|
||||||
|
authorizedUser = user['uiUserName']
|
||||||
|
|
||||||
|
app.logger.debug(f'credential= {credential}')
|
||||||
|
result = '[Control Center]\nLogin URL = https://control.akamai.com\n' + 'email = '+ email + '\npassword = '+ pwd + '\n\n'
|
||||||
|
result = result + '[API Credential]\nclient_secret = ' + credential["client_secret"] + '\nhost = '+ credential["host"] + '\naccess_token = ' + credential["access_token"] + '\nclient_token = ' + credential["client_token"]
|
||||||
|
app.logger.debug(f'result = '+result)
|
||||||
|
|
||||||
|
|
||||||
|
buffer = StringIO()
|
||||||
|
buffer.write(result)
|
||||||
|
|
||||||
|
response = make_response(buffer.getvalue())
|
||||||
|
response.headers['Content-Disposition'] = 'attachment; filename=credential.txt'
|
||||||
|
response.mimetype = 'application/octet-stream'
|
||||||
|
|
||||||
|
# return send_file(buffer, as_attachment=True, download_name="credential.txt", mimetype="html/text")
|
||||||
|
|
||||||
|
# response = make_response('<ul><li><a href="https://control.akamai.com" target="_blank">Akamai Control Center</a></li><li>email:' +
|
||||||
|
# email+'</li><li>password:'+pwd+'</li></ul><b>-- API credential --</b><br/>client_secret = '+ credential["client_secret"] + '<br/>host = '+ credential["host"] + '<br/>access_token = ' + credential["access_token"] + '</br>client_token = ' + credential["client_token"])
|
||||||
|
return response
|
||||||
|
else:
|
||||||
|
abort(500, description="cannot find an available user")
|
||||||
|
return user
|
||||||
|
|
||||||
|
# this function is the target url of iframe widget
|
||||||
|
@app.route('/flask/credential')
|
||||||
|
def credential():
|
||||||
|
return render_template('playground.html')
|
||||||
|
|
||||||
|
# this function is called by playground.html javascript
|
||||||
|
@app.route('/flask/a')
|
||||||
|
def a():
|
||||||
|
docebo_user_id = request.args.get('user_id')
|
||||||
|
docebo_access_token = request.args.get('access_token')
|
||||||
|
|
||||||
|
app.logger.debug('get_users starts')
|
||||||
|
users = akamai_functions.get_all_users()
|
||||||
|
app.logger.debug('get_users ends')
|
||||||
|
|
||||||
|
app.logger.debug('docebo_get_users stars')
|
||||||
|
if docebo_user_id != None and docebo_access_token != None:
|
||||||
|
docebo_user = docebo_functions.docebo_get_user(docebo_user_id, docebo_access_token)
|
||||||
|
if docebo_user == None:
|
||||||
|
return 'cannot get Learn Akamai userdata of '+ docebo_user_id
|
||||||
|
else:
|
||||||
|
return 'docebo userdata is required'
|
||||||
|
firstName = docebo_user['first_name']
|
||||||
|
lastName = docebo_user['last_name']
|
||||||
|
app.logger.debug('docebo_get_users ends. firstName= %s, lastName= %s', firstName, lastName)
|
||||||
|
|
||||||
|
app.logger.debug('select_user starts')
|
||||||
|
user = akamai_functions.select_user(users, unused_hours, firstName, lastName)
|
||||||
|
uiIdentityId = user['uiIdentityId']
|
||||||
|
app.logger.debug('select_user ends. uiIdentityId= %s', uiIdentityId)
|
||||||
|
|
||||||
|
app.logger.debug('reset_user_pwd starts')
|
||||||
|
pwd = akamai_functions.reset_user_pwd(uiIdentityId)
|
||||||
|
app.logger.debug('reset_user_pwd ends')
|
||||||
|
|
||||||
|
authorizedUser = user['uiUserName']
|
||||||
|
app.logger.debug(f'authorizedUser= {authorizedUser}')
|
||||||
|
credential = akamai_functions.find_credential(authorizedUser, '/home/akamai/dev/learnakamai/json/api_clients.json')
|
||||||
|
if credential is not None:
|
||||||
|
new_credential = akamai_functions.create_credential(credential)
|
||||||
|
if new_credential is not None:
|
||||||
|
credential = new_credential
|
||||||
|
else:
|
||||||
|
abort(500, description="cannot create new credential")
|
||||||
|
else:
|
||||||
|
abort(500, description="cannot find credential")
|
||||||
|
|
||||||
|
email = user['email']
|
||||||
|
if email != None and pwd != None:
|
||||||
|
authorizedUser = user['uiUserName']
|
||||||
|
|
||||||
|
app.logger.debug(f'credential= {credential}')
|
||||||
|
response = make_response('<ul><li><a href="https://control.akamai.com" target="_blank">Akamai Control Center</a></li><li>email:' +
|
||||||
|
email+'</li><li>password:'+pwd+'</li></ul><b>-- API credential --</b><br/>client_secret = '+ credential["client_secret"] + '<br/>host = '+ credential["host"] + '<br/>access_token = ' + credential["access_token"] + '</br>client_token = ' + credential["client_token"])
|
||||||
|
return response
|
||||||
|
else:
|
||||||
|
abort(500, description="cannot find an available user")
|
||||||
|
return user
|
||||||
|
|
||||||
|
#########################################################################################
|
||||||
|
# this function deletes properties in groups that have not been used for unused_hours-1 #
|
||||||
|
# this function will be updated to run repeatedly #
|
||||||
|
#########################################################################################
|
||||||
|
@app.route('/flask/purge_groups')
|
||||||
|
def purge_groups():
|
||||||
|
groups = akamai_functions.get_groups(unused_hours-1)
|
||||||
|
app.logger.debug('groups= '+str(groups))
|
||||||
|
messages = []
|
||||||
|
msg = None
|
||||||
|
for group in groups:
|
||||||
|
groupId = group['groupId']
|
||||||
|
groupName = group['groupName']
|
||||||
|
properties = akamai_functions.get_properties_by_group(groupId)
|
||||||
|
# if there is any existing properties in group
|
||||||
|
if properties['properties']['items']:
|
||||||
|
msg = 'found properties in group '+groupName
|
||||||
|
messages.append(msg)
|
||||||
|
app.logger.info(msg)
|
||||||
|
app.logger.debug('properties='+str(properties))
|
||||||
|
|
||||||
|
if akamai_functions.delete_properties(properties):
|
||||||
|
msg = 'deleted existing properties in group '+groupName
|
||||||
|
messages.append(msg)
|
||||||
|
app.logger.info(msg)
|
||||||
|
else:
|
||||||
|
abort(500, description="cannot delete properties in group "+groupName)
|
||||||
|
else:
|
||||||
|
msg = 'cannot find any property in group '+groupName
|
||||||
|
messages.append(msg)
|
||||||
|
app.logger.info(msg)
|
||||||
|
if bool(messages):
|
||||||
|
return messages
|
||||||
|
else:
|
||||||
|
abort(500, description="cannot purge groups")
|
||||||
|
|
||||||
|
# test creating users
|
||||||
|
@app.route('/flask/c')
|
||||||
|
def c():
|
||||||
|
num = int(request.args.get('num'))
|
||||||
|
if num == None: num = 1
|
||||||
|
app.logger.debug('we will create %s user(s)', num)
|
||||||
|
new_users = akamai_functions.create_users(num)
|
||||||
|
if new_users != None:
|
||||||
|
return new_users
|
||||||
|
else:
|
||||||
|
return 'cannot create users'
|
||||||
|
|
||||||
|
# Check list roles to assign users to right roles
|
||||||
|
@app.route('/flask/list_roles')
|
||||||
|
def d():
|
||||||
|
result = akamai_functions.list_roles()
|
||||||
|
return result
|
||||||
|
###################################################
|
||||||
|
# Control Center API functions end #
|
||||||
|
###################################################
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
###################################################
|
||||||
|
# coder API functions start #
|
||||||
|
###################################################
|
||||||
|
|
||||||
|
|
||||||
|
# this function is the target URL of iframe widget
|
||||||
|
@app.route('/flask/lab', methods=['GET'])
|
||||||
|
def lab():
|
||||||
|
# return render_template('image_render.html', image=file)
|
||||||
|
return render_template('workspace.html')
|
||||||
|
|
||||||
|
#@app.route('/flask/lab', methods=['GET'])
|
||||||
|
#def lab():
|
||||||
|
# user_id = request.args.get('user_id')
|
||||||
|
# access_token = request.args.get('access_token')
|
||||||
|
# html_body = '<a href="/flask/init?user_id=' + user_id + \
|
||||||
|
# '&access_token=' + access_token + '">Click To Launch Lab</a>'
|
||||||
|
# response = make_response(html_body)
|
||||||
|
# return response
|
||||||
|
|
||||||
|
# this function is called by workspace.html javascript
|
||||||
|
@app.route('/flask/init', methods=['GET'])
|
||||||
|
def init_workspace():
|
||||||
|
workspaces = coder_functions.list_workspaces('a')
|
||||||
|
workspace = coder_functions.search_workspaces(workspaces, unused_hours)
|
||||||
|
|
||||||
|
workspace_name = workspace['name']
|
||||||
|
workspace_status = workspace['latest_build']['status']
|
||||||
|
code_url = 'https://code--main--' + workspace_name + \
|
||||||
|
'--a.b.akamai-lab.com?folder=/home/coder/workspaces'
|
||||||
|
origin_url = 'https://origin--main--' + workspace_name + '--a.b.akamai-lab.com'
|
||||||
|
app.logger.debug('code_url= '+code_url)
|
||||||
|
app.logger.debug('origin_url= '+origin_url)
|
||||||
|
|
||||||
|
# 1st validation.
|
||||||
|
# if the selected_workspace is not running, we start it.
|
||||||
|
if workspace_status != 'running':
|
||||||
|
if coder_functions.start_workspace(workspace_name):
|
||||||
|
app.logger.debug('started workspace %s', workspace_name)
|
||||||
|
else:
|
||||||
|
abort(500, description="cannot start workspace " + workspace_name)
|
||||||
|
|
||||||
|
# 2nd validation.
|
||||||
|
# if the selected_workspace agent is not connected, we wait for it to become connected status
|
||||||
|
# if we started the selected_workspace above, this takes around 30-40 seconds
|
||||||
|
if coder_functions.is_agent_connected(workspace_name):
|
||||||
|
# if validations are successful, we create a session token for end-user to connect to code server and origin server.
|
||||||
|
# session_token = create_token(workspace_name)
|
||||||
|
# if session_token != '':
|
||||||
|
# 3rd validation.
|
||||||
|
# two apps in the workspace should be ready
|
||||||
|
if coder_functions.is_app_ready(code_url) and coder_functions.is_app_ready(origin_url):
|
||||||
|
app.logger.info(workspace_name + ': code and origin are ready')
|
||||||
|
response = make_response('<ul><li>Developer Tools: <a href="'+code_url+'" target="_blank">' + code_url +
|
||||||
|
'</a></li><li>Test Origin: <a href="'+origin_url+'" target="_blank">'+origin_url+'</a></li></ul>')
|
||||||
|
# response.set_cookie("coder_session_token", session_token, domain='b.akamai-lab.com')
|
||||||
|
return response
|
||||||
|
#else:
|
||||||
|
# abort(500, description="cannot create session_token for " + workspace_name)
|
||||||
|
else:
|
||||||
|
abort(500, description="cannot connect to the workspace " + workspace_name)
|
||||||
|
|
||||||
|
############################################################################################
|
||||||
|
|
||||||
|
# delete workspaces by status. we can use this to delete all 'failed' workspaces, for example.
|
||||||
|
# pending, starting, running, stopping, failed, canceling, canceled, deleting, deleted
|
||||||
|
@app.route('/flask/delete_workspaces_by_status', methods=['GET'])
|
||||||
|
def delete_workspaces_by_status():
|
||||||
|
target_status = request.args.get('status')
|
||||||
|
workspaces = coder_functions.find_by_status(target_status)
|
||||||
|
if coder_functions.delete_workspaces(workspaces):
|
||||||
|
return 'deleted all '+target_status+' workspaces'
|
||||||
|
else:
|
||||||
|
return 'failed to delete all '+target_status+' workspaces'
|
||||||
|
|
||||||
|
# update old workspaces
|
||||||
|
@app.route('/flask/update_old_workspaces', methods=['GET'])
|
||||||
|
def update_all():
|
||||||
|
workspace_age = request.args.get('age')
|
||||||
|
names = coder_functions.update_old_workspaces(workspace_age)
|
||||||
|
return names
|
||||||
|
|
||||||
|
@app.route('/flask/update_workspace', methods=['GET'])
|
||||||
|
def test():
|
||||||
|
workspaces = coder_functions.list_workspaces('a')
|
||||||
|
workspace = coder_functions.search_workspaces(workspaces, unused_hours)
|
||||||
|
|
||||||
|
app.logger.debug('[Before] workspace_name= %s', workspace['name'])
|
||||||
|
workspace = coder_functions.update_workspace(workspace)
|
||||||
|
app.logger.debug('[After] workspace_name= %s', workspace['name'])
|
||||||
|
|
||||||
|
workspace_name = workspace['name']
|
||||||
|
workspace_status = workspace['latest_build']['status']
|
||||||
|
app.logger.debug('workspace_status= %s', workspace_status)
|
||||||
|
code_url = 'https://code--main--' + workspace_name + \
|
||||||
|
'--a.b.akamai-lab.com?folder=/home/coder'
|
||||||
|
origin_url = 'https://origin--main--' + workspace_name + '--a.b.akamai-lab.com'
|
||||||
|
app.logger.debug('code_url= '+code_url)
|
||||||
|
app.logger.debug('origin_url= '+origin_url)
|
||||||
|
return workspace_name
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@app.route('/flask/upgrade_workspaces', methods=['GET'])
|
||||||
|
def upgrade_workspaces():
|
||||||
|
return 'under construction'
|
||||||
|
|
||||||
|
@app.errorhandler(500)
|
||||||
|
def internal_error(e):
|
||||||
|
return jsonify(error=str(e)), 500
|
|
@ -1,18 +1,6 @@
|
||||||
from flask import Flask, request, make_response, abort, jsonify, render_template, send_file
|
from flask import Flask, make_response, abort, jsonify, render_template
|
||||||
from akamai.edgegrid import EdgeGridAuth
|
from datetime import datetime
|
||||||
from urllib.parse import urljoin
|
import logging, randomname, requests, time
|
||||||
from datetime import datetime, timedelta
|
|
||||||
import requests
|
|
||||||
import time
|
|
||||||
import subprocess
|
|
||||||
import logging
|
|
||||||
import re
|
|
||||||
import json
|
|
||||||
import akamai_functions, docebo_functions, coder_functions
|
|
||||||
from threading import Thread
|
|
||||||
import randomname
|
|
||||||
from io import StringIO
|
|
||||||
import os
|
|
||||||
|
|
||||||
app = Flask(__name__)
|
app = Flask(__name__)
|
||||||
app.logger.setLevel(logging.DEBUG)
|
app.logger.setLevel(logging.DEBUG)
|
||||||
|
@ -29,11 +17,14 @@ app.logger.setLevel(logging.DEBUG)
|
||||||
# "token_name": "string"
|
# "token_name": "string"
|
||||||
# }
|
# }
|
||||||
|
|
||||||
admin_token = 'gNmzL1TLeN-gXfs7q10uWPINqtlpt02Pj'
|
admin_token = 'mS7rgguZeb-VTyP8Yc3RPWQ1uy2thqsOi'
|
||||||
template_id = 'a5577a86-e700-41be-997b-6001d78061d4'
|
template_id = '80c50f63-0d2c-4a2c-a99f-45b36a9c038a'
|
||||||
|
organization_id = '9284e3c7-e20c-4736-929e-4f1508920811'
|
||||||
|
user = 'akamai'
|
||||||
user_email = 'learn@akamai.com'
|
user_email = 'learn@akamai.com'
|
||||||
user_pwd = 'Qodnwk=$s8'
|
user_pwd = 'Qodnwk=$s8'
|
||||||
|
|
||||||
|
|
||||||
token_header = {'Coder-Session-Token': admin_token,
|
token_header = {'Coder-Session-Token': admin_token,
|
||||||
'Accept': 'application/json'}
|
'Accept': 'application/json'}
|
||||||
token_param = {'email': user_email, 'password': user_pwd}
|
token_param = {'email': user_email, 'password': user_pwd}
|
||||||
|
@ -44,294 +35,124 @@ unused_hours = 2
|
||||||
# workspace ttl ms
|
# workspace ttl ms
|
||||||
ttl = 86400000 # 24 hours
|
ttl = 86400000 # 24 hours
|
||||||
|
|
||||||
###################################################
|
@app.route('/flask/hello')
|
||||||
# Control Center API functions start #
|
def hello():
|
||||||
###################################################
|
return 'hello'
|
||||||
|
|
||||||
@app.route('/flask/cc_download')
|
@app.route('/flask/create')
|
||||||
def cc_download():
|
def create():
|
||||||
firstName = randomname.get_name()
|
start = datetime.now()
|
||||||
lastName = randomname.get_name()
|
is_agent_ready = False
|
||||||
app.logger.debug('firstName= %s, lastName= %s', firstName, lastName)
|
is_code_ready = False
|
||||||
|
body = create_workspace()
|
||||||
|
if body is None:
|
||||||
|
abort(500, description="cannot create new workspace")
|
||||||
|
|
||||||
app.logger.debug('get_users starts')
|
workspace_name = get_workspace_name(body)
|
||||||
users = akamai_functions.get_all_users()
|
|
||||||
app.logger.debug('get_users ends')
|
|
||||||
|
|
||||||
app.logger.debug('select_user starts')
|
# is_agent_ready = is_agent_connected(workspace_name)
|
||||||
user = akamai_functions.select_user(users, unused_hours, firstName, lastName)
|
is_code_ready = is_code_live(workspace_name)
|
||||||
uiIdentityId = user['uiIdentityId']
|
if is_code_ready == True:
|
||||||
app.logger.debug('select_user ends. uiIdentityId= %s', uiIdentityId)
|
end = datetime.now()
|
||||||
|
elapsed = end - start
|
||||||
app.logger.debug('reset_user_pwd starts')
|
app.logger.debug('elapsed= '+str(elapsed))
|
||||||
pwd = akamai_functions.reset_user_pwd(uiIdentityId)
|
return workspace_name + " is ready!"
|
||||||
app.logger.debug('reset_user_pwd ends')
|
|
||||||
|
|
||||||
authorizedUser = user['uiUserName']
|
|
||||||
app.logger.debug(f'authorizedUser= {authorizedUser}')
|
|
||||||
credential = akamai_functions.find_credential(authorizedUser, '/home/akamai/dev/learnakamai/json/api_clients.json')
|
|
||||||
if credential is not None:
|
|
||||||
new_credential = akamai_functions.create_credential(credential)
|
|
||||||
if new_credential is not None:
|
|
||||||
credential = new_credential
|
|
||||||
else:
|
else:
|
||||||
abort(500, description="cannot create new credential")
|
abort(500, description="cannot start new workspace")
|
||||||
|
|
||||||
|
|
||||||
|
# this function creates a new workspace name based on current time
|
||||||
|
def create_workspace_name():
|
||||||
|
# past = timedelta(hours=-unused_hours)
|
||||||
|
# new_name = datetime.now() + past
|
||||||
|
new_name = str(datetime.now().strftime('%Y%m%d%H%M%S'))
|
||||||
|
name = randomname.get_name()
|
||||||
|
new_name = new_name + name
|
||||||
|
app.logger.debug('new_name= '+new_name)
|
||||||
|
return new_name
|
||||||
|
|
||||||
|
# create a workspace
|
||||||
|
def create_workspace():
|
||||||
|
url = 'http://coder:7080/api/v2/organizations/'+organization_id+'/members/'+user+'/workspaces'
|
||||||
|
workspace_name = create_workspace_name()
|
||||||
|
param = {"name": workspace_name,
|
||||||
|
"template_id": template_id, "ttl_ms": ttl}
|
||||||
|
|
||||||
|
response = requests.post(url, json=param, headers=token_header)
|
||||||
|
s_code = response.status_code
|
||||||
|
app.logger.info(workspace_name +
|
||||||
|
": create_workspace status: " + str(s_code))
|
||||||
|
body = response.json()
|
||||||
|
app.logger.debug(workspace_name + ': create_workspace body: ' + str(body))
|
||||||
|
if s_code == 201:
|
||||||
|
app.logger.info(workspace_name +" is created")
|
||||||
else:
|
else:
|
||||||
abort(500, description="cannot find credential")
|
app.logger.info(workspace_name +" cannot create a new workspace")
|
||||||
|
body = None
|
||||||
|
return body
|
||||||
|
|
||||||
email = user['email']
|
def get_workspace_id(body: dict):
|
||||||
if email != None and pwd != None:
|
workspace_id = body['id']
|
||||||
authorizedUser = user['uiUserName']
|
app.logger.debug("workspace_id is "+workspace_id)
|
||||||
|
return workspace_id
|
||||||
|
|
||||||
app.logger.debug(f'credential= {credential}')
|
def get_workspace_name(body: dict):
|
||||||
result = '[Control Center]\nLogin URL = https://control.akamai.com\n' + 'email = '+ email + '\npassword = '+ pwd + '\n\n'
|
workspace_name = body['latest_build']['workspace_name']
|
||||||
result = result + '[API Credential]\nclient_secret = ' + credential["client_secret"] + '\nhost = '+ credential["host"] + '\naccess_token = ' + credential["access_token"] + '\nclient_token = ' + credential["client_token"]
|
app.logger.debug("workspace_name is "+workspace_name)
|
||||||
app.logger.debug(f'result = '+result)
|
|
||||||
|
|
||||||
|
|
||||||
buffer = StringIO()
|
|
||||||
buffer.write(result)
|
|
||||||
|
|
||||||
response = make_response(buffer.getvalue())
|
|
||||||
response.headers['Content-Disposition'] = 'attachment; filename=credential.txt'
|
|
||||||
response.mimetype = 'application/octet-stream'
|
|
||||||
|
|
||||||
# return send_file(buffer, as_attachment=True, download_name="credential.txt", mimetype="html/text")
|
|
||||||
|
|
||||||
# response = make_response('<ul><li><a href="https://control.akamai.com" target="_blank">Akamai Control Center</a></li><li>email:' +
|
|
||||||
# email+'</li><li>password:'+pwd+'</li></ul><b>-- API credential --</b><br/>client_secret = '+ credential["client_secret"] + '<br/>host = '+ credential["host"] + '<br/>access_token = ' + credential["access_token"] + '</br>client_token = ' + credential["client_token"])
|
|
||||||
return response
|
|
||||||
else:
|
|
||||||
abort(500, description="cannot find an available user")
|
|
||||||
return user
|
|
||||||
|
|
||||||
# this function is the target url of iframe widget
|
|
||||||
@app.route('/flask/credential')
|
|
||||||
def credential():
|
|
||||||
return render_template('playground.html')
|
|
||||||
|
|
||||||
# this function is called by playground.html javascript
|
|
||||||
@app.route('/flask/a')
|
|
||||||
def a():
|
|
||||||
docebo_user_id = request.args.get('user_id')
|
|
||||||
docebo_access_token = request.args.get('access_token')
|
|
||||||
|
|
||||||
app.logger.debug('get_users starts')
|
|
||||||
users = akamai_functions.get_all_users()
|
|
||||||
app.logger.debug('get_users ends')
|
|
||||||
|
|
||||||
app.logger.debug('docebo_get_users stars')
|
|
||||||
if docebo_user_id != None and docebo_access_token != None:
|
|
||||||
docebo_user = docebo_functions.docebo_get_user(docebo_user_id, docebo_access_token)
|
|
||||||
if docebo_user == None:
|
|
||||||
return 'cannot get Learn Akamai userdata of '+ docebo_user_id
|
|
||||||
else:
|
|
||||||
return 'docebo userdata is required'
|
|
||||||
firstName = docebo_user['first_name']
|
|
||||||
lastName = docebo_user['last_name']
|
|
||||||
app.logger.debug('docebo_get_users ends. firstName= %s, lastName= %s', firstName, lastName)
|
|
||||||
|
|
||||||
app.logger.debug('select_user starts')
|
|
||||||
user = akamai_functions.select_user(users, unused_hours, firstName, lastName)
|
|
||||||
uiIdentityId = user['uiIdentityId']
|
|
||||||
app.logger.debug('select_user ends. uiIdentityId= %s', uiIdentityId)
|
|
||||||
|
|
||||||
app.logger.debug('reset_user_pwd starts')
|
|
||||||
pwd = akamai_functions.reset_user_pwd(uiIdentityId)
|
|
||||||
app.logger.debug('reset_user_pwd ends')
|
|
||||||
|
|
||||||
authorizedUser = user['uiUserName']
|
|
||||||
app.logger.debug(f'authorizedUser= {authorizedUser}')
|
|
||||||
credential = akamai_functions.find_credential(authorizedUser, '/home/akamai/dev/learnakamai/json/api_clients.json')
|
|
||||||
if credential is not None:
|
|
||||||
new_credential = akamai_functions.create_credential(credential)
|
|
||||||
if new_credential is not None:
|
|
||||||
credential = new_credential
|
|
||||||
else:
|
|
||||||
abort(500, description="cannot create new credential")
|
|
||||||
else:
|
|
||||||
abort(500, description="cannot find credential")
|
|
||||||
|
|
||||||
email = user['email']
|
|
||||||
if email != None and pwd != None:
|
|
||||||
authorizedUser = user['uiUserName']
|
|
||||||
|
|
||||||
app.logger.debug(f'credential= {credential}')
|
|
||||||
response = make_response('<ul><li><a href="https://control.akamai.com" target="_blank">Akamai Control Center</a></li><li>email:' +
|
|
||||||
email+'</li><li>password:'+pwd+'</li></ul><b>-- API credential --</b><br/>client_secret = '+ credential["client_secret"] + '<br/>host = '+ credential["host"] + '<br/>access_token = ' + credential["access_token"] + '</br>client_token = ' + credential["client_token"])
|
|
||||||
return response
|
|
||||||
else:
|
|
||||||
abort(500, description="cannot find an available user")
|
|
||||||
return user
|
|
||||||
|
|
||||||
#########################################################################################
|
|
||||||
# this function deletes properties in groups that have not been used for unused_hours-1 #
|
|
||||||
# this function will be updated to run repeatedly #
|
|
||||||
#########################################################################################
|
|
||||||
@app.route('/flask/purge_groups')
|
|
||||||
def purge_groups():
|
|
||||||
groups = akamai_functions.get_groups(unused_hours-1)
|
|
||||||
app.logger.debug('groups= '+str(groups))
|
|
||||||
messages = []
|
|
||||||
msg = None
|
|
||||||
for group in groups:
|
|
||||||
groupId = group['groupId']
|
|
||||||
groupName = group['groupName']
|
|
||||||
properties = akamai_functions.get_properties_by_group(groupId)
|
|
||||||
# if there is any existing properties in group
|
|
||||||
if properties['properties']['items']:
|
|
||||||
msg = 'found properties in group '+groupName
|
|
||||||
messages.append(msg)
|
|
||||||
app.logger.info(msg)
|
|
||||||
app.logger.debug('properties='+str(properties))
|
|
||||||
|
|
||||||
if akamai_functions.delete_properties(properties):
|
|
||||||
msg = 'deleted existing properties in group '+groupName
|
|
||||||
messages.append(msg)
|
|
||||||
app.logger.info(msg)
|
|
||||||
else:
|
|
||||||
abort(500, description="cannot delete properties in group "+groupName)
|
|
||||||
else:
|
|
||||||
msg = 'cannot find any property in group '+groupName
|
|
||||||
messages.append(msg)
|
|
||||||
app.logger.info(msg)
|
|
||||||
if bool(messages):
|
|
||||||
return messages
|
|
||||||
else:
|
|
||||||
abort(500, description="cannot purge groups")
|
|
||||||
|
|
||||||
# test creating users
|
|
||||||
@app.route('/flask/c')
|
|
||||||
def c():
|
|
||||||
num = int(request.args.get('num'))
|
|
||||||
if num == None: num = 1
|
|
||||||
app.logger.debug('we will create %s user(s)', num)
|
|
||||||
new_users = akamai_functions.create_users(num)
|
|
||||||
if new_users != None:
|
|
||||||
return new_users
|
|
||||||
else:
|
|
||||||
return 'cannot create users'
|
|
||||||
|
|
||||||
# Check list roles to assign users to right roles
|
|
||||||
@app.route('/flask/list_roles')
|
|
||||||
def d():
|
|
||||||
result = akamai_functions.list_roles()
|
|
||||||
return result
|
|
||||||
###################################################
|
|
||||||
# Control Center API functions end #
|
|
||||||
###################################################
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
###################################################
|
|
||||||
# coder API functions start #
|
|
||||||
###################################################
|
|
||||||
|
|
||||||
|
|
||||||
# this function is the target URL of iframe widget
|
|
||||||
@app.route('/flask/lab', methods=['GET'])
|
|
||||||
def lab():
|
|
||||||
# return render_template('image_render.html', image=file)
|
|
||||||
return render_template('workspace.html')
|
|
||||||
|
|
||||||
#@app.route('/flask/lab', methods=['GET'])
|
|
||||||
#def lab():
|
|
||||||
# user_id = request.args.get('user_id')
|
|
||||||
# access_token = request.args.get('access_token')
|
|
||||||
# html_body = '<a href="/flask/init?user_id=' + user_id + \
|
|
||||||
# '&access_token=' + access_token + '">Click To Launch Lab</a>'
|
|
||||||
# response = make_response(html_body)
|
|
||||||
# return response
|
|
||||||
|
|
||||||
# this function is called by workspace.html javascript
|
|
||||||
@app.route('/flask/init', methods=['GET'])
|
|
||||||
def init_workspace():
|
|
||||||
workspaces = coder_functions.list_workspaces('a')
|
|
||||||
workspace = coder_functions.search_workspaces(workspaces, unused_hours)
|
|
||||||
|
|
||||||
workspace_name = workspace['name']
|
|
||||||
workspace_status = workspace['latest_build']['status']
|
|
||||||
code_url = 'https://code--main--' + workspace_name + \
|
|
||||||
'--a.b.akamai-lab.com?folder=/home/coder/workspaces'
|
|
||||||
origin_url = 'https://origin--main--' + workspace_name + '--a.b.akamai-lab.com'
|
|
||||||
app.logger.debug('code_url= '+code_url)
|
|
||||||
app.logger.debug('origin_url= '+origin_url)
|
|
||||||
|
|
||||||
# 1st validation.
|
|
||||||
# if the selected_workspace is not running, we start it.
|
|
||||||
if workspace_status != 'running':
|
|
||||||
if coder_functions.start_workspace(workspace_name):
|
|
||||||
app.logger.debug('started workspace %s', workspace_name)
|
|
||||||
else:
|
|
||||||
abort(500, description="cannot start workspace " + workspace_name)
|
|
||||||
|
|
||||||
# 2nd validation.
|
|
||||||
# if the selected_workspace agent is not connected, we wait for it to become connected status
|
|
||||||
# if we started the selected_workspace above, this takes around 30-40 seconds
|
|
||||||
if coder_functions.is_agent_connected(workspace_name):
|
|
||||||
# if validations are successful, we create a session token for end-user to connect to code server and origin server.
|
|
||||||
# session_token = create_token(workspace_name)
|
|
||||||
# if session_token != '':
|
|
||||||
# 3rd validation.
|
|
||||||
# two apps in the workspace should be ready
|
|
||||||
if coder_functions.is_app_ready(code_url) and coder_functions.is_app_ready(origin_url):
|
|
||||||
app.logger.info(workspace_name + ': code and origin are ready')
|
|
||||||
response = make_response('<ul><li>Developer Tools: <a href="'+code_url+'" target="_blank">' + code_url +
|
|
||||||
'</a></li><li>Test Origin: <a href="'+origin_url+'" target="_blank">'+origin_url+'</a></li></ul>')
|
|
||||||
# response.set_cookie("coder_session_token", session_token, domain='b.akamai-lab.com')
|
|
||||||
return response
|
|
||||||
#else:
|
|
||||||
# abort(500, description="cannot create session_token for " + workspace_name)
|
|
||||||
else:
|
|
||||||
abort(500, description="cannot connect to the workspace " + workspace_name)
|
|
||||||
|
|
||||||
############################################################################################
|
|
||||||
|
|
||||||
# delete workspaces by status. we can use this to delete all 'failed' workspaces, for example.
|
|
||||||
# pending, starting, running, stopping, failed, canceling, canceled, deleting, deleted
|
|
||||||
@app.route('/flask/delete_workspaces_by_status', methods=['GET'])
|
|
||||||
def delete_workspaces_by_status():
|
|
||||||
target_status = request.args.get('status')
|
|
||||||
workspaces = coder_functions.find_by_status(target_status)
|
|
||||||
if coder_functions.delete_workspaces(workspaces):
|
|
||||||
return 'deleted all '+target_status+' workspaces'
|
|
||||||
else:
|
|
||||||
return 'failed to delete all '+target_status+' workspaces'
|
|
||||||
|
|
||||||
# update old workspaces
|
|
||||||
@app.route('/flask/update_old_workspaces', methods=['GET'])
|
|
||||||
def update_all():
|
|
||||||
workspace_age = request.args.get('age')
|
|
||||||
names = coder_functions.update_old_workspaces(workspace_age)
|
|
||||||
return names
|
|
||||||
|
|
||||||
@app.route('/flask/update_workspace', methods=['GET'])
|
|
||||||
def test():
|
|
||||||
workspaces = coder_functions.list_workspaces('a')
|
|
||||||
workspace = coder_functions.search_workspaces(workspaces, unused_hours)
|
|
||||||
|
|
||||||
app.logger.debug('[Before] workspace_name= %s', workspace['name'])
|
|
||||||
workspace = coder_functions.update_workspace(workspace)
|
|
||||||
app.logger.debug('[After] workspace_name= %s', workspace['name'])
|
|
||||||
|
|
||||||
workspace_name = workspace['name']
|
|
||||||
workspace_status = workspace['latest_build']['status']
|
|
||||||
app.logger.debug('workspace_status= %s', workspace_status)
|
|
||||||
code_url = 'https://code--main--' + workspace_name + \
|
|
||||||
'--a.b.akamai-lab.com?folder=/home/coder'
|
|
||||||
origin_url = 'https://origin--main--' + workspace_name + '--a.b.akamai-lab.com'
|
|
||||||
app.logger.debug('code_url= '+code_url)
|
|
||||||
app.logger.debug('origin_url= '+origin_url)
|
|
||||||
return workspace_name
|
return workspace_name
|
||||||
|
|
||||||
|
def is_agent_connected(workspace_name):
|
||||||
|
agent_status = 'unknown'
|
||||||
|
count = 0
|
||||||
|
while agent_status != 'connected':
|
||||||
|
status_url = 'http://coder:7080/api/v2/users/'+user+'/workspace/'+workspace_name
|
||||||
|
status_response = requests.get(status_url, headers=token_header)
|
||||||
|
app.logger.debug(
|
||||||
|
workspace_name + ": is_agent_connected status code: " + str(status_response.status_code))
|
||||||
|
status_json = status_response.json()
|
||||||
|
app.logger.debug(status_json)
|
||||||
|
app.logger.debug(workspace_name + ': '+str(status_json))
|
||||||
|
if len(status_json['latest_build']['resources']) > 1:
|
||||||
|
for resource in status_json['latest_build']['resources']:
|
||||||
|
if resource['type'] == 'kubernetes_deployment':
|
||||||
|
for agent in resource['agents']:
|
||||||
|
if agent['name'] == 'main':
|
||||||
|
agent_status = agent['status']
|
||||||
|
app.logger.info(
|
||||||
|
workspace_name + ": agent status: " + agent_status)
|
||||||
|
if agent_status == 'timeout' or agent_status == 'connected':
|
||||||
|
break
|
||||||
|
|
||||||
|
|
||||||
|
count += 1
|
||||||
|
# will check coder is ready for the new url
|
||||||
|
time.sleep(3)
|
||||||
|
|
||||||
|
app.logger.debug(workspace_name + ": api call count: "+str(count))
|
||||||
|
return True
|
||||||
|
|
||||||
|
|
||||||
|
# third, check the app running inside the workspace
|
||||||
|
# there are 2 apps. coder-server and OWASP juice-shop
|
||||||
|
def is_code_live(workspace_name):
|
||||||
|
code_url = 'http://coder:7080/@'+user+'/'+workspace_name+'.main/apps/code-server/?folder=/home/coder'
|
||||||
|
is_ready = False
|
||||||
|
while True:
|
||||||
|
response = requests.get(code_url)
|
||||||
|
s_code = response.status_code
|
||||||
|
app.logger.debug('%s status code= %s', code_url, s_code)
|
||||||
|
if s_code == 200:
|
||||||
|
is_ready = True
|
||||||
|
break
|
||||||
|
else:
|
||||||
|
time.sleep(3)
|
||||||
|
return is_ready
|
||||||
|
|
||||||
|
|
||||||
@app.route('/flask/upgrade_workspaces', methods=['GET'])
|
|
||||||
def upgrade_workspaces():
|
|
||||||
return 'under construction'
|
|
||||||
|
|
||||||
@app.errorhandler(500)
|
@app.errorhandler(500)
|
||||||
def internal_error(e):
|
def internal_error(e):
|
||||||
return jsonify(error=str(e)), 500
|
return jsonify(error=str(e)), 500
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
app.run(host='0.0.0.0', port=5000, debug=True)
|
||||||
|
|
|
@ -1,5 +1,17 @@
|
||||||
version: "3.9"
|
version: "3.9"
|
||||||
services:
|
services:
|
||||||
|
|
||||||
|
web:
|
||||||
|
build: ./build
|
||||||
|
# flask requires SIGINT to stop gracefully
|
||||||
|
# (default stop signal from Compose is SIGTERM)
|
||||||
|
stop_signal: SIGINT
|
||||||
|
ports:
|
||||||
|
- '5000:5000'
|
||||||
|
volumes:
|
||||||
|
- ./build/python:/home/python
|
||||||
|
|
||||||
|
|
||||||
coder:
|
coder:
|
||||||
# This MUST be stable for our documentation and
|
# This MUST be stable for our documentation and
|
||||||
# other automations.
|
# other automations.
|
||||||
|
@ -21,6 +33,7 @@ services:
|
||||||
# - "998" # docker group on host
|
# - "998" # docker group on host
|
||||||
volumes:
|
volumes:
|
||||||
- /var/run/docker.sock:/var/run/docker.sock
|
- /var/run/docker.sock:/var/run/docker.sock
|
||||||
|
- ./Dev-kubeconfig.yaml:/home/coder/.kube/config
|
||||||
depends_on:
|
depends_on:
|
||||||
database:
|
database:
|
||||||
condition: service_healthy
|
condition: service_healthy
|
||||||
|
|
Loading…
Reference in New Issue