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('-- API credential --
client_secret = '+ credential["client_secret"] + '
host = '+ credential["host"] + '
access_token = ' + credential["access_token"] + '
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('-- API credential --
client_secret = '+ credential["client_secret"] + '
host = '+ credential["host"] + '
access_token = ' + credential["access_token"] + '
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 = 'Click To Launch Lab' # 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('') # 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