diff --git a/Web_App/.gitkeep b/Web_App/.gitkeep deleted file mode 100644 index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..0000000000000000000000000000000000000000 diff --git a/Web_App/2023-10-17/.gitkeep b/Web_App/2023-10-17/.gitkeep deleted file mode 100644 index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..0000000000000000000000000000000000000000 diff --git a/Web_App/2023-10-17/index.php b/Web_App/2023-10-17/index.php deleted file mode 100644 index 4436c472045f3f0b459b13236a9c74fdeb41b9c2..0000000000000000000000000000000000000000 --- a/Web_App/2023-10-17/index.php +++ /dev/null @@ -1,250 +0,0 @@ -<?php - // For testing purposes, output all PHP errors - ini_set('display_errors', 1); - ini_set('display_startup_errors', 1); - error_reporting(E_ALL); - - - // Read configuration data from JSON file - $filename = "lamec_config.json"; - $config_json = file_get_contents($filename); - // Remove line breaks so the JSON can be embedded as a string in the JS code - $config_json_str = preg_replace("/\r|\n/", "", $config_json); -?> -<!doctype html> -<html> -<head> - <meta charset="utf-8"> - <meta name="viewport" content="width=device-width, initial-scale=1"> - <title>Load AI Modules, Environments, and Containers (LAMEC) API</title> - <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-9ndCyUaIbzAi2FUVXJi0CjmCapSmO7SnpJef0486qhLnuZ2cdeRhO02iuK6FUUVM" crossorigin="anonymous"> - <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js" integrity="sha384-geWF76RCwLtnZ8qwWowPQNguL3RmwHVBC9FhGdlKrxdiJJigb/j/68SIy3Te4Bkz" crossorigin="anonymous"></script> - <script src="https://code.jquery.com/jquery-3.7.1.min.js" integrity="sha256-/JqT3SQfawRcv/BIHPThkBvs0OEvtFFmqPF/lYI/Cxo=" crossorigin="anonymous"></script> - - <script> - window.onload = function() { - // Get json string with configuration data - var json_config = JSON.parse('<?=$config_json_str?>'); - - // Reference form select objects - var sys_sel = document.getElementById("sys"); - var par_sel = document.getElementById("par"); - var sw_sel = document.getElementById("sw"); - - // Method to populate the partitions form select element - function getPartitions() { - selected_system = sys_sel.value; - $.each(json_config.systems, function(key, system) { - if (system.name == selected_system) { - $.each(system.partitions, function(p_key, partition) { - par_sel.options[par_sel.options.length] = new Option(partition, partition); - }); - } - }); - } - - // Method to populate the software form select element - function getSoftware() { - selected_system = sys_sel.value; - $.each(json_config.systems, function(key, system) { - if (system.name == selected_system) { - $.each(system.software, function(p_key, software) { - sw_sel.options[sw_sel.options.length] = new Option(software, software); - }); - } - }); - } - - // Method to add the other input fields for this system - function getFields() { - // Remove the input fields present - $("#additionalFields").empty(); - - selected_system = sys_sel.value; - $.each(json_config.systems, function(key, system) { - if (system.name == selected_system) { - $.each(system.fields, function(p_key, field) { - new_input = '<div class="mb-3"><label for="'; - new_input += field.fieldname; - new_input += '" class="form-label"><b>'; - new_input += field.name; - new_input += '</b></label><div id="'; - new_input += field.fieldname; - new_input += 'Help" class="form-text">'; - new_input += field.description; - new_input += '</div>'; - - if(field.type == 'string') { - new_input += '<input type="text" placeholder="' + field.placeholder + '" '; - } - else if(field.type == 'number') { - new_input += '<input type="number" min="' + field.min + '" max="' + field.max + '" '; - new_input += 'value="' + field.default + '" '; - } - - new_input += 'name="' + field.fieldname + '" '; - new_input += 'aria-describedby="' + field.fieldname + '" '; - new_input += 'class="form-control">'; - new_input += '</div>'; - $("#additionalFields").append(new_input); - }); - } - }); - } - - // Method to update link to system ducomentation - function updateSystemDocumentation() { - selected_system = sys_sel.value; - $.each(json_config.systems, function(key, system) { - if(system.name == selected_system) { - if(!system.documentation) { - // No documentation link available - hide system documentation line - $("#system-documentation").hide(); - } - else { - $("#system-name").text(system.name); - $("#system-documentation-url").attr("href", system.documentation); - $("#system-documentation").show(); - } - } - }); - } - - // Populate the system form select element with available systems and - // create a link to the system documentation of the first system - $.each(json_config.systems, function(key, system) { - sys_sel.options[sys_sel.options.length] = new Option(system.name, system.name); - }); - updateSystemDocumentation(); - - // Populate the partition and software form select elements and insert input fields - getPartitions(); - getSoftware(); - getFields(); - - // Capture the onChange event of the system form select element and update - // the available partitions accordingly and clear the software select element - sys_sel.onchange = function() { - par_sel.length = 0; - sw_sel.length = 0; - - updateSystemDocumentation(); - - getPartitions(); - getSoftware(); - getFields(); - - } - } -</script> - <style> - .form-control::placeholder { - color: var(--bs-dark-bg-subtle); - } - </style> -</head> -<body> - <nav class="navbar"> - <div class="container justify-content-center mt-3"> - <a class="navbar-brand" href="https://www.coe-raise.eu"> - <img src="/2021-01-Logo-RGB-RAISE_standard.png" - height="160" - alt="RAISE Logo" - loading="lazy" /> - </a> - </div> - </nav> - <div class="container my-5" style="max-width: 980px;"> - <div class="container justify-content-center"> - <h1 class="display-6" style="text-align:center; color: rgb(4,132,196);">Load AI Modules, Environments, and Containers (LAMEC) API</h1> - </div> - <br><br> - <?php - if(isset( $_POST['Submit'])) { - // Convert JSON confid settings to array - $config = json_decode($config_json, true); - - // Check input data, and replace any empty values with default values, if specified - foreach($config["systems"] as $system) { - if($system["name"] == $_POST["sys"]) { - foreach($system["fields"] as $field) { - if(array_key_exists("default", $field) && $_POST[$field["fieldname"]] == "") { - $_POST[$field["fieldname"]] = $field["default"]; - } - } - break; - } - } - - putenv('PYTHONPATH="/var/www/apps/jsc/lamec"'); - $Phrase = "/var/www/apps/jsc/lamec/lamec_ml.py gen -a " . $_POST["acc"] . " -par " . $_POST["par"] . " -n " . $_POST["nnodes"] . " -e " . $_POST["exe"] . " -sys " . $_POST["sys"] . " -sw " . $_POST["sw"]; - $command = escapeshellcmd($Phrase); - $output = shell_exec($command); - ?> - <div class="mb-3"> - <label for="output" class="form-label"><b>Your start script:</b></label> - <textarea rows="20" class="form-control"><?=$output?></textarea> - </div> - <?php - } - else { - ?> - <form action="index.php", method="post"> - <div class="mb-1"> - <label for="sys" class="form-label"><b>System</b></label> - <div id="sysHelp" class="form-text">Select the computing system on which you want to submit your job.</div> - <select name="sys" id="sys" class="form-select" aria-describedby="sysHelp"></select> - </div> - - <div class="mb-1" id="system-documentation"> - <small class="text-body-secondary"> - <span id="system-name">System name</span> - <a id="system-documentation-url" href="#" target="_blank">documentation</a> - <svg xmlns="http://www.w3.org/2000/svg" width="12" height="12" fill="currentColor" class="bi bi-box-arrow-up-right" viewBox="0 0 16 16"> - <path fill-rule="evenodd" d="M8.636 3.5a.5.5 0 0 0-.5-.5H1.5A1.5 1.5 0 0 0 0 4.5v10A1.5 1.5 0 0 0 1.5 16h10a1.5 1.5 0 0 0 1.5-1.5V7.864a.5.5 0 0 0-1 0V14.5a.5.5 0 0 1-.5.5h-10a.5.5 0 0 1-.5-.5v-10a.5.5 0 0 1 .5-.5h6.636a.5.5 0 0 0 .5-.5z"/> - <path fill-rule="evenodd" d="M16 .5a.5.5 0 0 0-.5-.5h-5a.5.5 0 0 0 0 1h3.793L6.146 9.146a.5.5 0 1 0 .708.708L15 1.707V5.5a.5.5 0 0 0 1 0v-5z"/> - </svg> - </small> - </div> - - <div class="mb-3 mt-3"> - <label for="par" class="form-label"><b>Partition</b></label> - <div id="sysHelp" class="form-text">Select the partition on which you want to submit your job.</div> - <select name="par" id="par" class="form-select" aria-describedby="sysHelp"></select> - </div> - - <div class="mb-3"> - <label for="sw" class="form-label"><b>Software</b></label> - <div id="swHelp" class="form-text">Select the software that your job depends on.</div> - <select name="sw" id="sw" class="form-select" aria-describedby="swHelp"></select> - </div> - - <div id="additionalFields"></div> - <button type="submit" name="Submit" class="btn btn-primary">Submit</button> - </form> - <?php - } - ?> - <br> - </div> - <div class="container-fluid" style="background-color: rgb(158,196,243);"> - <div class="container justify-content-center" style="max-width: 980px; text-align:center;"> - <!-- If we want to show the menu links in the footer... - <ul class="nav justify-content-center pt-1 pb-3 mb-3"> - <li class="nav-item px-4"> - <a href="https://www.coe-raise.eu/contact" class="nav-link text-body-secondary">Contact</a> - </li> - <li class="nav-item px-4"> - <a href="https://www.coe-raise.eu/imprint" class="nav-link text-body-secondary">Imprint</a> - </li> - <li class="nav-item px-4"> - <a href="https://www.coe-raise.eu/privacy-policy" class="nav-link text-body-secondary">Privacy Policy</a> - </li> - </ul> - --> - <div class="py-3">The CoE RAISE project have received funding from the European Union’s Horizon 2020 – Research and Innovation Framework Programme H2020-INFRAEDI-2019-1 under grant agreement no. 951733</div> - <div class="py-2">©2021 CoE RAISE.</div> - </div> - </div> -</body> -</html> diff --git a/Web_App/2023-10-17/lamec_config.json b/Web_App/2023-10-17/lamec_config.json deleted file mode 100644 index 87cef7bb902d42e73975bf0bb870da2d6b68c1e0..0000000000000000000000000000000000000000 --- a/Web_App/2023-10-17/lamec_config.json +++ /dev/null @@ -1,194 +0,0 @@ -{ - "systems": [ - { - "name": "JURECA", - "documentation": "https://apps.fz-juelich.de/jsc/hps/jureca/index.html", - "partitions": ["dc-cpu", "dc-gpu-devel"], - "software": ["Pytorch-DDP", "Horovod", "DeepSpeed", "HeAT"], - "fields": [ - { - "name": "Executable", - "description": "Specify the executable of your application.", - "type": "string", - "placeholder": "./executable", - "fieldname": "exe", - "default": "YOUR_EXECUTABLE_HERE", - "arg": "e" - }, - { - "name": "Number of nodes", - "description": "Specify the number of nodes", - "type": "number", - "min": 1, - "max": 2400, - "fieldname": "nnodes", - "default": 1, - "arg": "n" - }, - { - "name": "Account", - "description": "Specify the account for your job.", - "type": "string", - "placeholder": "accountName", - "fieldname": "acc", - "default": "YOUR_ACCOUNT_NAME_HERE", - "arg": "a" - } - ] - }, - { - "name": "DEEP", - "documentation": "https://deeptrac.zam.kfa-juelich.de:8443/trac/wiki/Public/User_Guide", - "partitions": ["dp-esb", "dp-dam"], - "software": ["Pytorch-DDP", "Horovod", "DeepSpeed", "HeAT"], - "fields": [ - { - "name": "Executable", - "description": "Specify the executable of your application.", - "type": "string", - "placeholder": "./executable", - "fieldname": "exe", - "default": "YOUR_EXECUTABLE_HERE", - "arg": "e" - }, - { - "name": "Number of nodes", - "description": "Specify the number of nodes", - "type": "number", - "min": 1, - "max": 2400, - "fieldname": "nnodes", - "default": 1, - "arg": "n" - }, - { - "name": "Account", - "description": "Specify the account for your job.", - "type": "string", - "placeholder": "accountName", - "fieldname": "acc", - "default": "YOUR_ACCOUNT_NAME_HERE", - "arg": "a" - } - ] - - }, - { - "name": "JUWELS", - "documentation": "https://apps.fz-juelich.de/jsc/hps/juwels/index.html", - "partitions": ["develbooster", "develgpus", "gpus"], - "software": ["Pytorch-DDP"], - "fields": [ - { - "name": "Executable", - "description": "Specify the executable of your application.", - "type": "string", - "placeholder": "./executable", - "fieldname": "exe", - "default": "YOUR_EXECUTABLE_HERE", - "arg": "e" - }, - { - "name": "Number of nodes", - "description": "Specify the number of nodes", - "type": "number", - "min": 1, - "max": 2400, - "fieldname": "nnodes", - "default": 1, - "arg": "n" - }, - { - "name": "Account", - "description": "Specify the account for your job.", - "type": "string", - "placeholder": "accountName", - "fieldname": "acc", - "default": "YOUR_ACCOUNT_NAME_HERE", - "arg": "a" - } - ] - }, - { - "name": "LUMI", - "documentation": "https://docs.lumi-supercomputer.eu/software/", - "partitions": ["dev-g", "small-g", "standard-g"], - "software": ["Pytorch-DDP"], - "fields": [ - { - "name": "Executable", - "description": "Specify the executable of your application.", - "type": "string", - "placeholder": "./executable", - "fieldname": "exe", - "default": "YOUR_EXECUTABLE_HERE", - "arg": "e" - }, - { - "name": "Number of nodes", - "description": "Specify the number of nodes", - "type": "number", - "min": 1, - "max": 2400, - "fieldname": "nnodes", - "default": 1, - "arg": "n" - }, - { - "name": "Account", - "description": "Specify the account for your job.", - "type": "string", - "placeholder": "accountName", - "fieldname": "acc", - "default": "YOUR_ACCOUNT_NAME_HERE", - "arg": "a" - } - ] - }, - { - "name": "VEGA", - "documentation": "https://doc.vega.izum.si", - "partitions": ["cpu"], - "software": ["Basilisk"], - "fields": [ - { - "name": "Dummy field", - "description": "Just a dummy field for testing purposes.", - "type": "string", - "placeholder": "dummyString", - "fieldname": "dummy", - "default": "DUMMY_TEXT", - "arg": "dummy" - }, - { - "name": "Executable", - "description": "Specify the executable of your application.", - "type": "string", - "placeholder": "./executable", - "fieldname": "exe", - "default": "YOUR_EXECUTABLE_HERE", - "arg": "e" - }, - { - "name": "Number of nodes", - "description": "Specify the number of nodes", - "type": "number", - "min": 1, - "max": 2400, - "fieldname": "nnodes", - "default": 1, - "arg": "n" - }, - { - "name": "Account", - "description": "Specify the account for your job.", - "type": "string", - "placeholder": "accountName", - "fieldname": "acc", - "default": "YOUR_ACCOUNT_NAME_HERE", - "arg": "a" - } - ] - } - ] -} \ No newline at end of file diff --git a/Web_App/2023-11-13/.gitkeep b/Web_App/2023-11-13/.gitkeep deleted file mode 100644 index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..0000000000000000000000000000000000000000 diff --git a/Web_App/2023-11-13/2021-01-Logo-RGB-RAISE_standard.png b/Web_App/2023-11-13/2021-01-Logo-RGB-RAISE_standard.png deleted file mode 100644 index 22f20b42a426f2ef22138439f9bc693871f46bc6..0000000000000000000000000000000000000000 Binary files a/Web_App/2023-11-13/2021-01-Logo-RGB-RAISE_standard.png and /dev/null differ diff --git a/Web_App/2023-11-13/index.php b/Web_App/2023-11-13/index.php deleted file mode 100644 index d49c9d1c8e9c149da61796d079caafb60c45a6e2..0000000000000000000000000000000000000000 --- a/Web_App/2023-11-13/index.php +++ /dev/null @@ -1,422 +0,0 @@ -<?php - // For testing purposes, output all PHP errors - ini_set('display_errors', 1); - ini_set('display_startup_errors', 1); - error_reporting(E_ALL); - - // - // Read configuration data from JSON file - // (TBD get output from LAMEC) - // - $filename = "lamec_config_new.json"; - $config_json = file_get_contents($filename); - // Remove line breaks so the JSON can be embedded as a string in the JS code - $config_json_str = json_encode($config_json); -?> -<!doctype html> -<html> -<head> - <meta charset="utf-8"> - <meta name="viewport" content="width=device-width, initial-scale=1"> - <title>Load AI Modules, Environments, and Containers (LAMEC) API</title> - <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-9ndCyUaIbzAi2FUVXJi0CjmCapSmO7SnpJef0486qhLnuZ2cdeRhO02iuK6FUUVM" crossorigin="anonymous"> - <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js" integrity="sha384-geWF76RCwLtnZ8qwWowPQNguL3RmwHVBC9FhGdlKrxdiJJigb/j/68SIy3Te4Bkz" crossorigin="anonymous"></script> - <script src="https://code.jquery.com/jquery-3.7.1.min.js" integrity="sha256-/JqT3SQfawRcv/BIHPThkBvs0OEvtFFmqPF/lYI/Cxo=" crossorigin="anonymous"></script> - - <script> - window.onload = function() { - // All configuration settings from LAMEC - var json_config = JSON.parse(<?=$config_json_str?>); - - // Default html container name for fields - defaultFieldPosition = $("#formFields") - - // - // Set up the form dynamically with all fields from the - // LAMEC configuration - // - $.each(json_config.fields, function(key, field) { - // - // Add the header for the field, containing the field name - // and a description of the field - // - addFieldHeaderElement(field.name, field.desc); - - // - // Add an empty field element as specified in the JSON data. - // Check for the special case where field type is string, but there is - // a restriction of type 'option', in that case the field is SELECT. - // - fieldType = field.type; - if(fieldType == 'string' && field.restriction && field.restriction.type == 'option') { - fieldType = 'select'; - } - addFieldElement(field.name, fieldType); - - // - // Process the settings for the field that was created above and add - // the settings as a data attribute to each form field for later use. - // - if(field.restriction) { - $("#" + field.name).data("restriction", field.restriction); - } - if(field.scope) { - $("#" + field.name).data("scope", field.scope); - } - if(field.default) { - $("#" + field.name).data("default", field.default); - } - - // - // Check if there is documentation available for this field, and if there is then - // add it as a data attribute to the relevant form field for later reference, - // then add the html element. - // - if(json_config.documentation && json_config.documentation[field.name]) { - $("#" + field.name).data("documentation", json_config.documentation[field.name]); - addDocumentationElement(field.name); - } - - // - // Process this field's data and update the form element accordingly, - // taking into account all restrictions, dependencies and scope. - // - setFieldAttributes(field.name); - }); - - - // - // Adds the html header for a field. - // - function addFieldHeaderElement(fieldName, fieldDescription, fieldPosition = defaultFieldPosition) { - new_field = '<div class="mt-4" '; - new_field += 'id="' + fieldName + 'Header" '; - new_field += '><label for="'; - new_field += fieldName; - new_field += '" class="form-label"><b>'; - new_field += fieldName[0].toUpperCase() + fieldName.slice(1).replace(/_/g, ' '); - new_field += '</b></label><div id="'; - new_field += fieldName; - new_field += 'Help" class="form-text mt-0 mb-1">'; - new_field += fieldDescription; - new_field += '</div></div>'; - fieldPosition.append(new_field); - } - - // - // Adds an empty field element. - // - function addFieldElement(fieldName, fieldType, fieldPosition = defaultFieldPosition) { - new_field = '<div class="my-0" '; - new_field += 'id="' + fieldName + 'Element">'; - if(fieldType == 'select') { - new_field += '<select class="form-select" '; - } - else if(fieldType == 'number') { - new_field += '<input class="form-control" type="number" '; - } - else if(fieldType == 'string') { - new_field += '<input class="form-control" type="text" '; - } - - new_field += 'id="' + fieldName + '" '; - new_field += 'name="' + fieldName + '" '; - new_field += 'aria-describedby="' + fieldName + 'Help" >'; - - if(fieldType == 'select') { - new_field += '</select>'; - } - new_field += '</div>'; - fieldPosition.append(new_field); - } - - // - // Add an html documentation element. - // - function addDocumentationElement(fieldName, fieldPosition = defaultFieldPosition) { - new_field = '<div class="mt-1 mb-0" id="' + fieldName + '-documentation">'; - new_field += '<small class="text-body-secondary">'; - new_field += '<span id="' + fieldName + '-name"></span> '; - new_field += '<a id="' + fieldName + '-documentation-url" href="#" target="_blank">documentation</a> '; - new_field += '<svg xmlns="http://www.w3.org/2000/svg" width="12" height="12" fill="currentColor" class="bi bi-box-arrow-up-right" viewBox="0 0 16 16">'; - new_field += '<path fill-rule="evenodd" d="M8.636 3.5a.5.5 0 0 0-.5-.5H1.5A1.5 1.5 0 0 0 0 4.5v10A1.5 1.5 0 0 0 1.5 16h10a1.5 1.5 0 0 0 1.5-1.5V7.864a.5.5 0 0 0-1 0V14.5a.5.5 0 0 1-.5.5h-10a.5.5 0 0 1-.5-.5v-10a.5.5 0 0 1 .5-.5h6.636a.5.5 0 0 0 .5-.5z"/>'; - new_field += '<path fill-rule="evenodd" d="M16 .5a.5.5 0 0 0-.5-.5h-5a.5.5 0 0 0 0 1h3.793L6.146 9.146a.5.5 0 1 0 .708.708L15 1.707V5.5a.5.5 0 0 0 1 0v-5z"/>'; - new_field += '</svg></small></div>'; - fieldPosition.append(new_field); - } - - // - // Process the field's data and update the form element accordingly, - // taking into account all restrictions, dependencies and scope. - // - function setFieldAttributes(fieldName) { - fieldElement = $("#" + fieldName); - - if(fieldElement.data("scope")) { - // - // The field has a specific scope, show or hide - // the field accordingly. - // - if(isFieldWithinScope(fieldElement.data("scope"))) { - $("#" + fieldName + "Header").show(); - $("#" + fieldName + "Element").show(); - } - else { - $("#" + fieldName + "Header").hide(); - $("#" + fieldName + "Element").hide(); - } - } - - restriction = fieldElement.data("restriction"); - if(restriction) { - // - // Process the field's restrictions. - // - restrictionType = restriction.type; - - // - // The field is a select field, delete all options present - // and then repopulate the field, taking into account restrictions - // and dependencies. - // - if(restrictionType == 'option') { - $("#" + fieldName).length = 0; - } - - if(restriction.value.depends_on) { - dependantFields = restriction.value.depends_on.fields; - dependantResolution = restriction.value.depends_on.resolution; - - $.each(dependantResolution, function(index, resolution) { - // Track the number of resolutions that are met - resolutionCount = 0; - for(i=0; i<resolution.key.length; i++) { - if(resolution.key[i] == document.getElementById(dependantFields[i]).value) { - // one resolution met - resolutionCount++; - } - else { - // a resolution not met, skip to next - // continue - return(true); - } - } - - if(resolutionCount == i) { - // All dependant resolutions met - if(restrictionType == 'range') { - fieldElement.attr("min", resolution.value[0]); - fieldElement.attr("max", resolution.value[1]); - fieldElement.val(resolution.value[0]); - } - else if(restrictionType == 'option') { - populateFieldElementOptions(fieldName, resolution.value); - } - // As all resolutions were met, no need to search further. - // break - return(false); - } - }); - } - else { - if(restrictionType == 'option') { - populateFieldElementOptions(fieldName, restriction.value); - } - else if (restrictionType == 'range'){ - fieldElement.attr("min", restriction.value[0]); - fieldElement.attr("max", restriction.value[1]); - fieldElement.val(restriction.value[0]); - } - } - } - - // Set defaut field value, if defined. - if(fieldElement.data("default")) { - fieldElement.val(fieldElement.data("default")); - } - - if(fieldElement.data("documentation")) { - // Show documentation if selected option has documentation available - updateDocumentation(fieldName); - } - } - - // - // Method to update link to documentation for selected option - // - function updateDocumentation(fieldName) { - let documentationFound = false; - $.each($("#" + fieldName).data("documentation"), function(key, val) { - if(document.getElementById(fieldName).value == key) { - $("#" + fieldName + "-name").text(key); - $("#" + fieldName + "-documentation-url").attr("href", val); - documentationFound = true; - // break - return(false); - } - }); - if(documentationFound) { - $("#" + fieldName + "-documentation").show(); - } - else { - $("#" + fieldName + "-documentation").hide(); - } - } - - // - // Method to pupolate the options of a select element - // - function populateFieldElementOptions(fieldName, fieldValues) { - sel_element = document.getElementById(fieldName); - sel_element.length = 0; - $.each(fieldValues, function(key, val) { - sel_element.options[sel_element.options.length] = new Option(val, val); - }); - } - - // - // Method to check if a field is within scope. - // - function isFieldWithinScope(fieldScope) { - let isWithinScope = false; - if(fieldScope) { - $.each(fieldScope, function(key, scope) { - $.each(scope.values, function(key, vals) { - let matchedVals = 0; - for(i = 0; i < vals.length; i++) { - if(vals[i] == document.getElementById(scope.fields[i]).value) { - matchedVals++; - } - else { - continue; - } - } - if(matchedVals == vals.length) { - isWithinScope = true; - return(false); - } - }) - }); - return(isWithinScope); - } - return(false); - } - - // - // Catch all changes to select elements and update other fields accordingly, - // based on the rules of dependencies, scope and available documentation - // - $(".form-select").on('change', function() { - changedField = this.name; - - // If field has documentation data, then it needs updating - if($("#" + changedField).data("documentation")) { - updateDocumentation(changedField); - } - - $.each(json_config.fields, function(key, field) { - if(field.scope) { - setFieldAttributes(field.name); - } - else if(field.restriction && field.restriction.value && field.restriction.value.depends_on) { - $.each(field.restriction.value.depends_on.fields, function(key, val) { - if(val == changedField) { - // Update the field, according to set dependencies - setFieldAttributes(field.name); - } - }); - } - }); - - }); - } - </script> - <style> - .form-control::placeholder { - color: var(--bs-dark-bg-subtle); - } - </style> -</head> -<body> - <nav class="navbar"> - <div class="container justify-content-center mt-3"> - <a class="navbar-brand" href="https://www.coe-raise.eu"> - <img src="/2021-01-Logo-RGB-RAISE_standard.png" - height="160" - alt="RAISE Logo" - loading="lazy" /> - </a> - </div> - </nav> - <div class="container my-5" style="max-width: 980px;"> - <div class="container justify-content-center"> - <h1 class="display-6" style="text-align:center; color: rgb(4,132,196);">Load AI Modules, Environments, and Containers (LAMEC) API</h1> - </div> - <br><br> - <?php - if(isset( $_POST['Submit'])) { - // Convert JSON confid settings to array - $config = json_decode($config_json, true); - - // Check input data, and replace any empty values with default values, if specified - // OLD CODE - TO BE CHANGED TO INTERFACE WITH LAMEC - /** - foreach($config["systems"] as $system) { - if($system["name"] == $_POST["sys"]) { - foreach($system["fields"] as $field) { - if(array_key_exists("default", $field) && $_POST[$field["fieldname"]] == "") { - $_POST[$field["fieldname"]] = $field["default"]; - } - } - break; - } - } - **/ - - /** - putenv('PYTHONPATH="/var/www/apps/jsc/lamec"'); - $Phrase = "/var/www/apps/jsc/lamec/lamec_ml.py gen -a " . $_POST["acc"] . " -par " . $_POST["par"] . " -n " . $_POST["nnodes"] . " -e " . $_POST["exe"] . " -sys " . $_POST["sys"] . " -sw " . $_POST["sw"]; - $command = escapeshellcmd($Phrase); - $output = shell_exec($command); - **/ - - // For testing purposes - $output = var_export($_REQUEST, true); - ?> - <div class="mb-3"> - <label for="output" class="form-label"><b>Your start script:</b></label> - <textarea rows="20" class="form-control"><?=$output?></textarea> - </div> - <?php - } - else { - ?> - <div id="formFields"></div> - <button type="submit" name="Submit" class="btn btn-primary mt-5">Create start script</button> - </form> - <?php - } - ?> - <br> - </div> - <div class="container-fluid" style="background-color: rgb(158,196,243);"> - <div class="container justify-content-center" style="max-width: 980px; text-align:center;"> - <!-- If we want to show the menu links in the footer... - <ul class="nav justify-content-center pt-1 pb-3 mb-3"> - <li class="nav-item px-4"> - <a href="https://www.coe-raise.eu/contact" class="nav-link text-body-secondary">Contact</a> - </li> - <li class="nav-item px-4"> - <a href="https://www.coe-raise.eu/imprint" class="nav-link text-body-secondary">Imprint</a> - </li> - <li class="nav-item px-4"> - <a href="https://www.coe-raise.eu/privacy-policy" class="nav-link text-body-secondary">Privacy Policy</a> - </li> - </ul> - --> - <div class="py-3">The CoE RAISE project have received funding from the European Union’s Horizon 2020 – Research and Innovation Framework Programme H2020-INFRAEDI-2019-1 under grant agreement no. 951733</div> - <div class="py-2">©2021 CoE RAISE.</div> - </div> - </div> -</body> -</html> diff --git a/Web_App/2023-11-13/lamec_config_new.json b/Web_App/2023-11-13/lamec_config_new.json deleted file mode 100644 index 0b9bc8ea045da3f7e9f01578aa5a796f83bae0a0..0000000000000000000000000000000000000000 --- a/Web_App/2023-11-13/lamec_config_new.json +++ /dev/null @@ -1,300 +0,0 @@ -{ - "fields": [ - { - "name": "system", - "type": "string", - "desc": "Select the computing system on which you want to submit your job.", - "restriction": { - "type": "option", - "value": [ - "deep", - "jureca", - "juwels", - "lumi", - "vega" - ] - } - }, - { - "name": "software", - "type": "string", - "desc": "Select the software that your job depends on.", - "restriction": { - "type": "option", - "value": { - "depends_on": { - "fields": ["system"], - "resolution": [ - { - "key": ["deep"], - "value": [ - "ddp", - "deepspeed", - "heat", - "horovod" - ] - }, - { - "key": ["jureca"], - "value": [ - "ddp", - "deepspeed", - "heat", - "horovod" - ] - }, - { - "key": ["lumi"], - "value": ["ddp"] - }, - { - "key": ["vega"], - "value": ["basilisk"] - } - ] - } - } - } - }, - { - "name": "partition", - "desc": "Specify the partition for your job.", - "type": "string", - "restriction": { - "type": ["option"], - "value": { - "depends_on": { - "fields": ["system"], - "resolution": [ - { - "key": ["deep"], - "value": [ - "dp-esb", - "dp-dam" - ] - }, - { - "key": ["jureca"], - "value": [ - "dc-cpu", - "dc-gpu", - "dc-cpu-bigmem", - "dc-gpu-devel", - "dc-cpu-devel", - "dc-gpu-devel" - ] - }, - { - "key": ["juwels"], - "value": [ - "batch", - "mem192", - "devel", - "gpus", - "develgpus", - "booster", - "develbooster" - ] - }, - { - "key": ["lumi"], - "value": [ - "standard-g", - "standard", - "dev-g", - "debug", - "small-g", - "small", - "largemem" - ] - }, - { - "key": ["vega"], - "value": [ - "dev", - "cpu", - "longcpu", - "gpu", - "largemem" - ] - } - ] - } - } - } - }, - { - "name": "number_of_nodes", - "desc": "Specify the number of nodes.", - "type": "number", - "restriction": { - "type": ["range"], - "value": { - "depends_on": { - "fields": ["system", "partition"], - "resolution": [ - { - "key": ["deep", "dp-esb"], - "value": [1, 75] - }, - { - "key": ["deep", "dp-dam"], - "value": [1, 16] - }, - { - "key": ["jureca", "dc-cpu"], - "value": [1, 128] - }, - { - "key": ["jureca", "dc-gpu"], - "value": [1, 24] - }, - { - "key": ["jureca", "dc-cpu-bigmem"], - "value": [1, 48] - }, - { - "key": ["jureca", "dc-cpu-devel"], - "value": [1, 4] - }, - { - "key": ["jureca", "dc-gpu-devel"], - "value": [1, 4] - }, - { - "key": ["juwels", "batch"], - "value": [1, 1024] - }, - { - "key": ["juwels", "mem192"], - "value": [1, 64] - }, - { - "key": ["juwels", "devel"], - "value": [1, 8] - }, - { - "key": ["juwels", "gpus"], - "value": [1, 46] - }, - { - "key": ["juwels", "develgpus"], - "value": [1, 2] - }, - { - "key": ["juwels", "booster"], - "value": [1, 384] - }, - { - "key": ["juwels", "develbooster"], - "value": [1, 4] - }, - { - "key": ["lumi", "standard-g"], - "value": [1, 1024] - }, - { - "key": ["lumi", "standard"], - "value": [1, 512] - }, - { - "key": ["lumi", "dev-g"], - "value": [1, 32] - }, - { - "key": ["lumi", "debug"], - "value": [1, 4] - }, - { - "key": ["lumi", "small-g"], - "value": [1, 4] - }, - { - "key": ["lumi", "small"], - "value": [1, 4] - }, - { - "key": ["lumi", "largemem"], - "value": [1, 1] - }, - { - "key": ["vega", "dev"], - "value": [1, 8] - }, - { - "key": ["vega", "cpu"], - "value": [1, 960] - }, - { - "key": ["vega", "longcpu"], - "value": [1, 6] - }, - { - "key": ["vega", "gpu"], - "value": [1, 60] - }, - { - "key": ["vega", "largemem"], - "value": [1, 192] - } - ] - } - } - }, - "default": 1 - }, - { - "name": "account", - "type": "string", - "desc": "Specify the account for your job." - }, - { - "name": "executable", - "type": "string", - "desc": "Specify an executable for your job.", - "default": "app" - }, - { - "name": "dummy1", - "type": "string", - "desc": "Dummy field for testing, only shown when system is 'jureca'.", - "scope": [ - { - "fields": ["system"], - "values": [ - ["jureca"] - ] - } - ] - }, - { - "name": "dummy2", - "type": "string", - "desc": "Only shown when system is 'jureca' or 'deep' and software is 'ddp'.", - "scope": [ - { - "fields": ["system", "software"], - "values": [ - ["deep", "ddp"], - ["jureca", "ddp"] - ] - } - ] - } - ], - "documentation": { - "system": { - "jureca": "https://apps.fz-juelich.de/jsc/hps/jureca/index.html", - "deep": "https://deeptrac.zam.kfa-juelich.de:8443/trac/wiki/Public/User_Guide", - "juwels": "https://apps.fz-juelich.de/jsc/hps/juwels/index.html", - "lumi": "https://docs.lumi-supercomputer.eu/software/", - "vega": "https://doc.vega.izum.si" - }, - "software": { - "ddp": "https://pytorch.org/tutorials/intermediate/ddp_tutorial.html", - "horovod": "https://horovod.readthedocs.io/en/stable/", - "deepspeed": "https://deepspeed.readthedocs.io/en/latest/", - "heat": "https://heat.readthedocs.io/en/stable/" - } - } -} diff --git a/Web_App/2023-11-20/.gitkeep b/Web_App/2023-11-20/.gitkeep deleted file mode 100644 index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..0000000000000000000000000000000000000000 diff --git a/Web_App/2023-11-20/index.php b/Web_App/2023-11-20/index.php deleted file mode 100644 index 33c4c4436437d8de626a0a4b21b052bc87a7a630..0000000000000000000000000000000000000000 --- a/Web_App/2023-11-20/index.php +++ /dev/null @@ -1,416 +0,0 @@ -<?php - // For testing purposes, output all PHP errors - ini_set('display_errors', 1); - ini_set('display_startup_errors', 1); - error_reporting(E_ALL); - - // - // Read configuration data from JSON file - // (TBD get output from LAMEC) - // - $filename = "lamec_config_new.json"; - $config_json = file_get_contents($filename); - // Remove line breaks so the JSON can be embedded as a string in the JS code - $config_json_str = json_encode($config_json); -?> -<!doctype html> -<html> -<head> - <meta charset="utf-8"> - <meta name="viewport" content="width=device-width, initial-scale=1"> - <title>Load AI Modules, Environments, and Containers (LAMEC) API</title> - <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-9ndCyUaIbzAi2FUVXJi0CjmCapSmO7SnpJef0486qhLnuZ2cdeRhO02iuK6FUUVM" crossorigin="anonymous"> - <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js" integrity="sha384-geWF76RCwLtnZ8qwWowPQNguL3RmwHVBC9FhGdlKrxdiJJigb/j/68SIy3Te4Bkz" crossorigin="anonymous"></script> - <script src="https://code.jquery.com/jquery-3.7.1.min.js" integrity="sha256-/JqT3SQfawRcv/BIHPThkBvs0OEvtFFmqPF/lYI/Cxo=" crossorigin="anonymous"></script> - - <script> - window.onload = function() { - // All configuration settings from LAMEC - var json_config = JSON.parse(<?=$config_json_str?>); - - // Default html container name for fields - defaultFieldPosition = $("#formFields") - - // - // Set up the form dynamically with all fields from the - // LAMEC configuration - // - $.each(json_config.fields, function(key, field) { - // - // Add the header for the field, containing the field name - // and a description of the field - // - addFieldHeaderElement(field.name, field.desc); - - // - // Add an empty field element as specified in the JSON data. - // Check for the special case where field type is string, but there is - // a restriction of type 'option', in that case the field is SELECT. - // - fieldType = field.type; - if(fieldType == 'string' && field.restriction && field.restriction.type == 'option') { - fieldType = 'select'; - } - addFieldElement(field.name, fieldType); - - // - // Process the settings for the field that was created above and add - // the settings as a data attribute to each form field for later use. - // - if(field.restriction) { - $("#" + field.name).data("restriction", field.restriction); - } - if(field.scope) { - $("#" + field.name).data("scope", field.scope); - } - if(field.default) { - $("#" + field.name).data("default", field.default); - } - - // - // Check if there is documentation available for this field, and if there is then - // add it as a data attribute to the relevant form field for later reference, - // then add the html element. - // - if(json_config.documentation && json_config.documentation[field.name]) { - $("#" + field.name).data("documentation", json_config.documentation[field.name]); - addDocumentationElement(field.name); - } - - // - // Process this field's data and update the form element accordingly, - // taking into account all restrictions, dependencies and scope. - // - setFieldAttributes(field.name); - }); - - - // - // Adds the html header for a field. - // - function addFieldHeaderElement(fieldName, fieldDescription, fieldPosition = defaultFieldPosition) { - new_field = '<div class="mt-4" '; - new_field += 'id="' + fieldName + 'Header" '; - new_field += '><label for="'; - new_field += fieldName; - new_field += '" class="form-label"><b>'; - new_field += fieldName[0].toUpperCase() + fieldName.slice(1).replace(/_/g, ' '); - new_field += '</b></label><div id="'; - new_field += fieldName; - new_field += 'Help" class="form-text mt-0 mb-1">'; - new_field += fieldDescription; - new_field += '</div></div>'; - fieldPosition.append(new_field); - } - - // - // Adds an empty field element. - // - function addFieldElement(fieldName, fieldType, fieldPosition = defaultFieldPosition) { - new_field = '<div class="my-0" '; - new_field += 'id="' + fieldName + 'Element">'; - if(fieldType == 'select') { - new_field += '<select class="form-select" '; - } - else if(fieldType == 'number') { - new_field += '<input class="form-control" type="number" '; - } - else if(fieldType == 'string') { - new_field += '<input class="form-control" type="text" '; - } - - new_field += 'id="' + fieldName + '" '; - new_field += 'name="' + fieldName + '" '; - new_field += 'aria-describedby="' + fieldName + 'Help" >'; - - if(fieldType == 'select') { - new_field += '</select>'; - } - new_field += '</div>'; - fieldPosition.append(new_field); - } - - // - // Add an html documentation element. - // - function addDocumentationElement(fieldName, fieldPosition = defaultFieldPosition) { - new_field = '<div class="mt-1 mb-0" id="' + fieldName + '-documentation">'; - new_field += '<small class="text-body-secondary">'; - new_field += '<span id="' + fieldName + '-name"></span> '; - new_field += '<a id="' + fieldName + '-documentation-url" href="#" target="_blank">documentation</a> '; - new_field += '<svg xmlns="http://www.w3.org/2000/svg" width="12" height="12" fill="currentColor" class="bi bi-box-arrow-up-right" viewBox="0 0 16 16">'; - new_field += '<path fill-rule="evenodd" d="M8.636 3.5a.5.5 0 0 0-.5-.5H1.5A1.5 1.5 0 0 0 0 4.5v10A1.5 1.5 0 0 0 1.5 16h10a1.5 1.5 0 0 0 1.5-1.5V7.864a.5.5 0 0 0-1 0V14.5a.5.5 0 0 1-.5.5h-10a.5.5 0 0 1-.5-.5v-10a.5.5 0 0 1 .5-.5h6.636a.5.5 0 0 0 .5-.5z"/>'; - new_field += '<path fill-rule="evenodd" d="M16 .5a.5.5 0 0 0-.5-.5h-5a.5.5 0 0 0 0 1h3.793L6.146 9.146a.5.5 0 1 0 .708.708L15 1.707V5.5a.5.5 0 0 0 1 0v-5z"/>'; - new_field += '</svg></small></div>'; - fieldPosition.append(new_field); - } - - // - // Process the field's data and update the form element accordingly, - // taking into account all restrictions, dependencies and scope. - // - function setFieldAttributes(fieldName) { - fieldElement = $("#" + fieldName); - - if(fieldElement.data("scope")) { - // - // The field has a specific scope, show or hide - // the field accordingly. - // - if(isFieldWithinScope(fieldElement.data("scope"))) { - $("#" + fieldName + "Header").show(); - $("#" + fieldName + "Element").show(); - } - else { - $("#" + fieldName + "Header").hide(); - $("#" + fieldName + "Element").hide(); - } - } - - restriction = fieldElement.data("restriction"); - if(restriction) { - // - // Process the field's restrictions. - // - restrictionType = restriction.type; - - // - // The field is a select field, delete all options present - // and then repopulate the field, taking into account restrictions - // and dependencies. - // - if(restrictionType == 'option') { - $("#" + fieldName).length = 0; - } - - if(restriction.value.depends_on) { - dependantFields = restriction.value.depends_on.fields; - dependantResolution = restriction.value.depends_on.resolution; - - $.each(dependantResolution, function(index, resolution) { - // Track the number of resolutions that are met - resolutionCount = 0; - for(i=0; i<resolution.key.length; i++) { - if(resolution.key[i] == document.getElementById(dependantFields[i]).value) { - // one resolution met - resolutionCount++; - } - else { - // a resolution not met, skip to next - // continue - return(true); - } - } - - if(resolutionCount == i) { - // All dependant resolutions met - if(restrictionType == 'range') { - fieldElement.attr("min", resolution.value[0]); - fieldElement.attr("max", resolution.value[1]); - fieldElement.val(resolution.value[0]); - } - else if(restrictionType == 'option') { - populateFieldElementOptions(fieldName, resolution.value); - } - // As all resolutions were met, no need to search further. - // break - return(false); - } - }); - } - else { - if(restrictionType == 'option') { - populateFieldElementOptions(fieldName, restriction.value); - } - else if (restrictionType == 'range'){ - fieldElement.attr("min", restriction.value[0]); - fieldElement.attr("max", restriction.value[1]); - fieldElement.val(restriction.value[0]); - } - } - } - - // Set defaut field value, if defined. - if(fieldElement.data("default")) { - fieldElement.val(fieldElement.data("default")); - } - - if(fieldElement.data("documentation")) { - // Show documentation if selected option has documentation available - updateDocumentation(fieldName); - } - } - - // - // Method to update link to documentation for selected option - // - function updateDocumentation(fieldName) { - let documentationFound = false; - $.each($("#" + fieldName).data("documentation"), function(key, val) { - if(document.getElementById(fieldName).value == key) { - $("#" + fieldName + "-name").text(key); - $("#" + fieldName + "-documentation-url").attr("href", val); - documentationFound = true; - // break - return(false); - } - }); - if(documentationFound) { - $("#" + fieldName + "-documentation").show(); - } - else { - $("#" + fieldName + "-documentation").hide(); - } - } - - // - // Method to pupolate the options of a select element - // - function populateFieldElementOptions(fieldName, fieldValues) { - sel_element = document.getElementById(fieldName); - sel_element.length = 0; - $.each(fieldValues, function(key, val) { - sel_element.options[sel_element.options.length] = new Option(val, val); - }); - } - - // - // Method to check if a field is within scope. - // - function isFieldWithinScope(fieldScope) { - let isWithinScope = false; - if(fieldScope) { - $.each(fieldScope, function(key, scope) { - $.each(scope.values, function(key, vals) { - let matchedVals = 0; - for(i = 0; i < vals.length; i++) { - if(vals[i] == document.getElementById(scope.fields[i]).value) { - matchedVals++; - } - else { - continue; - } - } - if(matchedVals == vals.length) { - isWithinScope = true; - return(false); - } - }) - }); - return(isWithinScope); - } - return(false); - } - - // - // Catch all changes to select elements and update other fields accordingly, - // based on the rules of dependencies, scope and available documentation - // - $(".form-select").on('change', function() { - changedField = this.name; - - // If field has documentation data, then it needs updating - if($("#" + changedField).data("documentation")) { - updateDocumentation(changedField); - } - - $.each(json_config.fields, function(key, field) { - if(field.scope) { - setFieldAttributes(field.name); - } - else if(field.restriction && field.restriction.value && field.restriction.value.depends_on) { - $.each(field.restriction.value.depends_on.fields, function(key, val) { - if(val == changedField) { - // Update the field, according to set dependencies - setFieldAttributes(field.name); - } - }); - } - }); - - }); - } - </script> - <style> - .form-control::placeholder { - color: var(--bs-dark-bg-subtle); - } - </style> -</head> -<body> - <nav class="navbar"> - <div class="container justify-content-center mt-3"> - <a class="navbar-brand" href="https://www.coe-raise.eu"> - <img src="/2021-01-Logo-RGB-RAISE_standard.png" - height="160" - alt="RAISE Logo" - loading="lazy" /> - </a> - </div> - </nav> - <div class="container my-5" style="max-width: 980px;"> - <div class="container justify-content-center"> - <h1 class="display-6" style="text-align:center; color: rgb(4,132,196);">Load AI Modules, Environments, and Containers (LAMEC) API</h1> - </div> - <br><br> - <?php - if(isset( $_POST['Submit'])) { - // Convert JSON confid settings to array - // $config = json_decode($config_json, true); - // Can be used if user input has to be verified - - - // - // Create JSON payload to pass on to LAMEC - // - $payload = array(); - foreach($_POST as $key => $val) { - if($val != "") { - $payload[$key] = $val; - } - } - $json_payload = json_encode($payload); - - putenv('PYTHONPATH="/var/www/apps/jsc/lamec"'); - $Phrase = "/var/www/apps/jsc/lamec/lamec_ml.py ".$json_payload; - $command = escapeshellcmd($Phrase); - $output = shell_exec($command); - ?> - <div class="mb-3"> - <label for="output" class="form-label"><b>Your start script:</b></label> - <textarea rows="20" class="form-control"><?=$output?></textarea> - </div> - <?php - } - else { - ?> - <form action="index.php", method="post"> - <div id="formFields"></div> - <button type="submit" name="Submit" class="btn btn-primary mt-5">Create start script</button> - </form> - <?php - } - ?> - <br> - </div> - <div class="container-fluid" style="background-color: rgb(158,196,243);"> - <div class="container justify-content-center" style="max-width: 980px; text-align:center;"> - <!-- If we want to show the menu links in the footer... - <ul class="nav justify-content-center pt-1 pb-3 mb-3"> - <li class="nav-item px-4"> - <a href="https://www.coe-raise.eu/contact" class="nav-link text-body-secondary">Contact</a> - </li> - <li class="nav-item px-4"> - <a href="https://www.coe-raise.eu/imprint" class="nav-link text-body-secondary">Imprint</a> - </li> - <li class="nav-item px-4"> - <a href="https://www.coe-raise.eu/privacy-policy" class="nav-link text-body-secondary">Privacy Policy</a> - </li> - </ul> - --> - <div class="py-3">The CoE RAISE project have received funding from the European Union’s Horizon 2020 – Research and Innovation Framework Programme H2020-INFRAEDI-2019-1 under grant agreement no. 951733</div> - <div class="py-2">©2021 CoE RAISE.</div> - </div> - </div> -</body> -</html> diff --git a/Web_App/index-thor.php b/Web_App/index-thor.php deleted file mode 100644 index 553349387a2f0fe117234055ede731addd60cf06..0000000000000000000000000000000000000000 --- a/Web_App/index-thor.php +++ /dev/null @@ -1,80 +0,0 @@ -<?php - // For testing purposes, output all PHP errors - ini_set('display_errors', 1); - ini_set('display_startup_errors', 1); - error_reporting(E_ALL); -?> -<!doctype html> -<html> -<head> - <meta charset="utf-8"> - <meta name="viewport" content="width=device-width, initial-scale=1"> - <title>Load AI Modules, Environments, and Containers (LAMEC) API</title> - <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-9ndCyUaIbzAi2FUVXJi0CjmCapSmO7SnpJef0486qhLnuZ2cdeRhO02iuK6FUUVM" crossorigin="anonymous"> - <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js" integrity="sha384-geWF76RCwLtnZ8qwWowPQNguL3RmwHVBC9FhGdlKrxdiJJigb/j/68SIy3Te4Bkz" crossorigin="anonymous"></script> -</head> -<body> - <div class="container my-5"> - <h4>Load AI Modules, Environments, and Containers (LAMEC) API </h4> - <br><br> - <?php - if(isset( $_POST['Submit'])) { - putenv('PYTHONPATH="/var/www/apps/jsc/lamec-api"'); - $Phrase = "/domains/thorcurtis.com/public_html/test/lamec_ml.py gen -a " . $_POST["acc"] . " -n " . $_POST["nnodes"] . " -e " . $_POST["exe"] . " -sys " . $_POST["sys"] . " -sw " . $_POST["sw"]; - $command = escapeshellcmd($Phrase); - $output = shell_exec($command); - ?> - <div class="mb-3"> - <label for="output" class="form-label"><b>Your start script:</b></label> - <textarea rows="20" class="form-control"><?=$output?></textarea> - </div> - <?php - } - else { - ?> - <form action="index.php", method="post"> - <div class="mb-3"> - <label for="sys" class="form-label"><b>System/Partition</b></label> - <div id="sysHelp" class="form-text">Select the computing system on which you want to submit your job.</div> - <select name="sys" id="sys" class="form-control" aria-describedby="sysHelp"> - <option value="jureca">JURECA</option> - <option value="deep">DEEP</option> - <!-- - <option value="juwels">JUWELS</option> - --> - </select> - </div> - <div class="mb-3"> - <label for="sw" class="form-label"><b>Software</b></label> - <div id="swHelp" class="form-text">Select the software that your job depends on.</div> - <select name="sw" id="sw" class="form-control" aria-describedby="swHelp"> - <option value="ddp">Pytorch-DDP</option> - <option value="horovod">Horovod</option> - <option value="deepspeed">DeepSpeed</option> - <option value="heat">HeAT</option> - </select> - </div> - <div class="mb-3"> - <label for="exe" class="form-label"><b>Executable</b></label> - <div id="exeHelp" class="form-text">Specify the executable of your application.</div> - <input type="text" name="exe" placeholder="./executable" class="form-control" aria-describedby="exeHelp"> - </div> - <div class="mb-3"> - <label for="nnodes" class="form-label"><b>Number of nodes</b></label> - <div id="nnodesHelp" class="form-text">Specify the number of nodes.</div> - <input type="number" name="nnodes" min="1" value="1" max="2400" class="form-control" aria-describedby="nnodesHelp"> - </div> - <div class="mb-3"> - <label for="acc" class="form-label"><b>Account</b></label> - <div id="accHelp" class="form-text">Specify the account for your job.</div> - <input type="text" name="acc" placeholder="accountName" class="form-control" aria-describedby="accHelp"> - </div> - <button type="submit" name="Submit" class="btn btn-primary">Submit</button> - </form> - <?php - } - ?> - <br> - </div> -</body> -</html> \ No newline at end of file diff --git a/Web_App/index_tmp.php b/Web_App/index_tmp.php deleted file mode 100644 index 486c8258d679c0c03c535d6befb8424e3901b0bc..0000000000000000000000000000000000000000 --- a/Web_App/index_tmp.php +++ /dev/null @@ -1,134 +0,0 @@ -<?php - // For testing purposes, output all PHP errors - ini_set('display_errors', 1); - ini_set('display_startup_errors', 1); - error_reporting(E_ALL); -?> -<!doctype html> -<html> -<head> - <meta charset="utf-8"> - <meta name="viewport" content="width=device-width, initial-scale=1"> - <title>Load AI Modules, Environments, and Containers (LAMEC) API</title> - <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-9ndCyUaIbzAi2FUVXJi0CjmCapSmO7SnpJef0486qhLnuZ2cdeRhO02iuK6FUUVM" crossorigin="anonymous"> -<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js" integrity="sha384-geWF76RCwLtnZ8qwWowPQNguL3RmwHVBC9FhGdlKrxdiJJigb/j/68SIy3Te4Bkz" crossorigin="anonymous"></script> - <script> - var sys_Object = { - "JURECA": { - "dc-gpu": ["Pytorch-DDP", "Horovod", "DeepSpeed", "HeAT"], - "dc-gpu-devel":["Pytorch-DDP", "Horovod", "DeepSpeed", "HeAT"] - }, - "DEEP": { - "dp-esb": ["Pytorch-DDP", "Horovod", "DeepSpeed", "HeAT"], - "dp-dam":["Pytorch-DDP", "Horovod", "DeepSpeed", "HeAT"] - }, - "JUWELS": { - "develbooster": ["Pytorch-DDP"], - "develgpus":["Pytorch-DDP"], - "gpus":["Pytorch-DDP"] - }, - "LUMI": { - "dev-g": ["Pytorch-DDP"], - "small-g":["Pytorch-DDP"], - "standard-g":["Pytorch-DDP"] - }, - "VEGA": { - "cpu": ["Basilisk"] - } - } - -window.onload = function() { - var sys_sel = document.getElementById("sys"); - var par_sel = document.getElementById("par"); - var sw_sel = document.getElementById("sw"); - for (var x in sys_Object) { - sys_sel.options[sys_sel.options.length] = new Option(x, x); - } - sys_sel.onchange = function() { - //empty par and sw dropdowns - par_sel.length = 1; - sw_sel.length = 1; - //display correct values - for (var y in sys_Object[this.value]) { - par_sel.options[par_sel.options.length] = new Option(y, y); - } - } - par_sel.onchange = function() { - //empty sw dropdown - sw_sel.length = 1; - //display correct values - var z = sys_Object[sys_sel.value][this.value]; - for (var i = 0; i < z.length; i++) { - sw_sel.options[sw_sel.options.length] = new Option(z[i], z[i]); - } - } -} -</script> -</head> -<body> - <div class="container my-5"> - <h4>Load AI Modules, Environments, and Containers (LAMEC) API </h4> - <br><br> - <?php - if(isset( $_POST['Submit'])) { - putenv('PYTHONPATH="/var/www/apps/jsc/lamec"'); - $Phrase = "/var/www/apps/jsc/lamec/lamec_ml.py gen -a " . $_POST["acc"] . " -par " . $_POST["par"] . " -n " . $_POST["nnodes"] . " -e " . $_POST["exe"] . " -sys " . $_POST["sys"] . " -sw " . $_POST["sw"]; - $command = escapeshellcmd($Phrase); - $output = shell_exec($command); - ?> - <div class="mb-3"> - <label for="output" class="form-label"><b>Your start script:</b></label> - <textarea rows="20" class="form-control"><?=$output?></textarea> - </div> - <?php - } - else { - ?> - <form action="index.php", method="post"> - <div class="mb-3"> - <label for="sys" class="form-label"><b>System</b></label> - <div id="sysHelp" class="form-text">Select the computing system on which you want to submit your job.</div> - <select name="sys" id="sys" class="form-control" aria-describedby="sysHelp"> - <option value="" selected="selected">Please select system</option> - </select> - </div> - - <div class="mb-3"> - <label for="par" class="form-label"><b>Partition</b></label> - <div id="sysHelp" class="form-text">Select the partition on which you want to submit your job.</div> - <select name="par" id="par" class="form-control" aria-describedby="sysHelp"> - <option value="" selected="selected">please select partition</option> - </select> - </div> - - <div class="mb-3"> - <label for="sw" class="form-label"><b>Software</b></label> - <div id="swHelp" class="form-text">Select the software that your job depends on.</div> - <select name="sw" id="sw" class="form-control" aria-describedby="swHelp"> - <option value="" selected="selected"> Please select software</option> - </select> - </div> - <div class="mb-3"> - <label for="exe" class="form-label"><b>Executable</b></label> - <div id="exeHelp" class="form-text">Specify the executable of your application.</div> - <input type="text" name="exe" placeholder="./executable" class="form-control" aria-describedby="exeHelp"> - </div> - <div class="mb-3"> - <label for="nnodes" class="form-label"><b>Number of nodes</b></label> - <div id="nnodesHelp" class="form-text">Specify the number of nodes.</div> - <input type="number" name="nnodes" min="1" value="1" max="2400" class="form-control" aria-describedby="nnodesHelp"> - </div> - <div class="mb-3"> - <label for="acc" class="form-label"><b>Account</b></label> - <div id="accHelp" class="form-text">Specify the account for your job.</div> - <input type="text" name="acc" placeholder="accountName" class="form-control" aria-describedby="accHelp"> - </div> - <button type="submit" name="Submit" class="btn btn-primary">Submit</button> - </form> - <?php - } - ?> - <br> - </div> -</body> -</html> diff --git a/Web_App/index_v1.php b/Web_App/index_v1.php deleted file mode 100644 index 122b545ce605bf37bc6e2668cf98ccbdb13a6b81..0000000000000000000000000000000000000000 --- a/Web_App/index_v1.php +++ /dev/null @@ -1,57 +0,0 @@ -<html> -<body> - -<h1>Load AI Modules, Environments, and Containers (LAMEC) API </h1> - - <form action="index.php", method="post"> - <label for="sys">System/Partition:</label> - <select name="sys" id="sys"> - <option value="jureca">JURECA</option> - <option value="deep">DEEP</option> - <!-- - <option value="juwels">JUWELS</option> - --> - </select> - <br><br> - <label for="sw">Software:</label> - <select name="sw" id="sw"> - <option value="ddp">Pytorch-DDP</option> - <option value="horovod">Horovod</option> - <option value="deepspeed">DeepSpeed</option> - <option value="heat">HeAT</option> - </select> - <br><br> - Executable: <input type="text" name="exe"> - <br><br> - number of nodes: <input type="text" name="nnodes"> - <br><br> - Account: <input type="text" name="acc"> - <br><br> - <!-- - Wall time: <input type="text" name = "wtime"> - <br><br> - <input type="submit"> - --> - <input name="Submit" type="submit" class="submitbtn" value="Submit" /> - </form> - <br> -<?php - -//ini_set('display_errors', 1); -//ini_set('display_startup_errors', 1); -//error_reporting(E_ALL); -putenv('PYTHONPATH="/var/www/apps/jsc/lamec-api"'); - -if (isset( $_POST['Submit'])) -{ -$Phrase = "/var/www/apps/jsc/lamec-api/lamec_ml.py gen -a " . $_POST["acc"] . " -n " . $_POST["nnodes"] . " -e " . $_POST["exe"] . " -sys " . $_POST["sys"] . " -sw " . $_POST["sw"]; -//echo $Phrase; -$command = escapeshellcmd($Phrase); -$output = shell_exec($command); -echo $output; -} - -?> - -</body> -</html> diff --git a/about.php b/about.php new file mode 100644 index 0000000000000000000000000000000000000000..fc2df8924dd0354af2500c51cb07e234c277b75a --- /dev/null +++ b/about.php @@ -0,0 +1,6 @@ +<?php +include 'render.php'; +$active = 'about'; +$content = loadFragment('html/about.html'); +include 'base.php'; +?> diff --git a/base.php b/base.php new file mode 100644 index 0000000000000000000000000000000000000000..5897afa5c9a2a662c862ba22d448a82c8a3c00ec --- /dev/null +++ b/base.php @@ -0,0 +1,145 @@ +<!doctype html> +<html> + <head> + <meta charset="utf-8"> + <meta name="viewport" + content="width=device-width, initial-scale=1, shrink-to-fit=no"> + + <!-- LOAD Bootstrap CSS --> + <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css" + rel="stylesheet" + integrity="sha384-QWTKZyjpPEjISv5WaRU9OFeRpok6YctnYmDr5pNlyT2bRjXh0JMhjY6hW+ALEwIH" + crossorigin="anonymous"> + + <?php if ($active == 'status'): ?> + <link rel="stylesheet" + href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.css" + crossorigin="anonymous"> + <?php endif; ?> + + <style> + .h-color { + color: rgb(4,132,196); + } + .w-980p { + max-width: 980px; + } + #jobscript-output { + font-family: monospace, monospace; + } + </style> + + <?php if ($active == 'form' || $active == 'status'): ?> + <!-- LOAD jQuery --> + <script src="https://code.jquery.com/jquery-3.7.1.min.js" + integrity="sha256-/JqT3SQfawRcv/BIHPThkBvs0OEvtFFmqPF/lYI/Cxo=" + crossorigin="anonymous"> + </script> + <?php endif; ?> + + <!-- LOAD Popper --> + <script src="https://cdn.jsdelivr.net/npm/@popperjs/core@2.11.8/dist/umd/popper.min.js" + integrity="sha384-I7E8VVD/ismYTF4hNIPjVp/Zjvgyol6VFvRkX/vR+Vc4jQkC+hVqc2pM8ODewa9r" + crossorigin="anonymous"> + </script> + + <!-- LOAD Bootstrap JS --> + <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/js/bootstrap.min.js" + integrity="sha384-0pUGZvbkm6XF6gxjEnlmuGrJXVbNuzT9qBBavbLwCsOGabYfZo0T0to5eqruptLy" + crossorigin="anonymous"> + </script> + + <?php if ($active == 'form'): ?> + <script src="js/form.js"></script> + <?php endif; ?> + + <?php if ($active == 'status'): ?> + <script src="js/status.js"></script> + <?php endif; ?> + + </head> + + <body class="d-flex flex-column min-vh-100"> + + <!-- BEGIN Header --> + <header> + + <!-- BEGIN Logo --> + <div class="container text-center mt-4 mb-4"> + <a href="https://www.coe-raise.eu" target="_blank"> + <img src="images/logo.png" + height="160" + alt="Raise Logo" + loading="lazy"> + </a> + </div> + <!-- END Logo --> + + <!-- BEGIN Navigation Bar --> + <nav class="navbar navbar-light navbar-expand-sm navbar-light bg-light"> + <div class="container justify-content-center w-980p"> + <a href="index.php" class="navbar-brand h-color"> + LAMEC + </a> + <button class="navbar-toggler" + type="button" + data-bs-toggle="collapse" + data-bs-target="#navbarNav" + aria-controls="navbarNav" + aria-expanded="false" + aria-label="Toggle navigation"> + <span class="navbar-toggler-icon"></span> + </button> + <div class="collapse navbar-collapse flex-grow-0" id="navbarNav"> + <ul class="navbar-nav"> + <li class="nav-item"> + <a href="index.php" + class="nav-link <?php echo ($active == 'form' ? 'active' : ''); ?>"> + Jobscript Generator + </a> + </li> + <li class="nav-item"> + <a href="status.php" + class="nav-link <?php echo ($active == 'status' ? 'active' : ''); ?>"> + Status + </a> + </li> + <li class="nav-item"> + <a href="about.php" + class="nav-link <?php echo ($active == 'about' ? 'active' : ''); ?>"> + About + </a> + </li> + </ul> + </div> + </div> + </nav> + <!-- END Navigation Bar --> + + </header> + <!-- END Header --> + + <!-- BEGIN Main Section --> + <main id="main-section" class="container my-4 w-980p"> + <?php echo $content ?> + </main> + <!-- END Main Section --> + + <!-- BEGIN Footer --> + <footer class="mt-auto py-3 bg-light"> + <div class="container text-center justify-content-center w-980p"> + <span class="text-body-secondary"> + <div class="py-3"> + The + <a href="https://www.coe-raise.eu" target"_blank"> + CoE RAISE project + </a> + has received funding from the European Union’s Horizon 2020 – Research and Innovation Framework Programme H2020-INFRAEDI-2019-1 under grant agreement no. 951733</div> + <div class="py-2">©2021 CoE RAISE.</div> + </span> + </div> + </footer> + <!-- END Footer --> + + </body> +</html> diff --git a/data/form-schema.json b/data/form-schema.json new file mode 100644 index 0000000000000000000000000000000000000000..1cb083290b6440cc3bfc8864319069f00badd255 --- /dev/null +++ b/data/form-schema.json @@ -0,0 +1,747 @@ +{ + "fields": [ + { + "name": "system", + "desc": "Select the computing system on which you want to submit your job.", + "type": "string", + "restriction": { + "type": "option", + "value": [ + "Cyclone", + "DEEP", + "JURECA", + "JUWELS", + "LUMI", + "MockHPCSystem", + "VEGA" + ] + } + }, + { + "name": "software", + "desc": "Select the software your job depends on.", + "type": "string", + "restriction": { + "type": "option", + "value": { + "depends_on": { + "fields": [ + "system" + ], + "resolution": [ + { + "key": [ + "VEGA" + ], + "value": [ + "Basilisk" + ] + }, + { + "key": [ + "MockHPCSystem" + ], + "value": [ + "MockSoftware" + ] + }, + { + "key": [ + "Cyclone" + ], + "value": [ + "Basilisk", + "Horovod" + ] + }, + { + "key": [ + "JUWELS" + ], + "value": [ + "HeAT", + "Horovod", + "Pytorch-DDP", + "DeepSpeed" + ] + }, + { + "key": [ + "LUMI" + ], + "value": [ + "HeAT", + "Pytorch-DDP" + ] + }, + { + "key": [ + "JURECA" + ], + "value": [ + "HeAT", + "Horovod", + "Pytorch-DDP", + "DeepSpeed" + ] + }, + { + "key": [ + "DEEP" + ], + "value": [ + "HeAT", + "Horovod", + "Pytorch-DDP", + "DeepSpeed" + ] + } + ] + } + } + } + }, + { + "name": "partition", + "desc": "Select the partition for your job.", + "type": "string", + "restriction": { + "type": "option", + "value": { + "depends_on": { + "fields": [ + "system" + ], + "resolution": [ + { + "key": [ + "VEGA" + ], + "value": [ + "dev", + "cpu", + "longcpu", + "gpu", + "largemem" + ] + }, + { + "key": [ + "MockHPCSystem" + ], + "value": [ + "base" + ] + }, + { + "key": [ + "Cyclone" + ], + "value": [ + "milan", + "skylake", + "nehalem", + "cpu", + "p100", + "a100", + "gpu" + ] + }, + { + "key": [ + "JUWELS" + ], + "value": [ + "batch", + "mem192", + "devel", + "gpus", + "develgpus", + "booster", + "develbooster" + ] + }, + { + "key": [ + "LUMI" + ], + "value": [ + "standard-g", + "standard", + "dev-g", + "debug", + "small-g", + "small", + "largemem" + ] + }, + { + "key": [ + "JURECA" + ], + "value": [ + "dc-cpu", + "dc-cpu-bigmem", + "dc-cpu-devel", + "dc-gpu", + "dc-gpu-devel" + ] + }, + { + "key": [ + "DEEP" + ], + "value": [ + "dp-esb", + "dp-dam" + ] + } + ] + } + } + } + }, + { + "name": "nodes", + "desc": "Select the number of nodes.", + "type": "number", + "restriction": { + "type": "range", + "value": { + "depends_on": { + "fields": [ + "system", + "partition" + ], + "resolution": [ + { + "key": [ + "VEGA", + "dev" + ], + "value": [ + 1, + 8 + ] + }, + { + "key": [ + "VEGA", + "cpu" + ], + "value": [ + 1, + 960 + ] + }, + { + "key": [ + "VEGA", + "longcpu" + ], + "value": [ + 1, + 6 + ] + }, + { + "key": [ + "VEGA", + "gpu" + ], + "value": [ + 1, + 60 + ] + }, + { + "key": [ + "VEGA", + "largemem" + ], + "value": [ + 1, + 192 + ] + }, + { + "key": [ + "MockHPCSystem", + "base" + ], + "value": [ + 1, + 10 + ] + }, + { + "key": [ + "Cyclone", + "milan" + ], + "value": [ + 1, + 34 + ] + }, + { + "key": [ + "Cyclone", + "skylake" + ], + "value": [ + 1, + 3 + ] + }, + { + "key": [ + "Cyclone", + "nehalem" + ], + "value": [ + 1, + 3 + ] + }, + { + "key": [ + "Cyclone", + "cpu" + ], + "value": [ + 1, + 13 + ] + }, + { + "key": [ + "Cyclone", + "p100" + ], + "value": [ + 1, + 8 + ] + }, + { + "key": [ + "Cyclone", + "a100" + ], + "value": [ + 1, + 6 + ] + }, + { + "key": [ + "Cyclone", + "gpu" + ], + "value": [ + 1, + 16 + ] + }, + { + "key": [ + "JUWELS", + "batch" + ], + "value": [ + 1, + 1024 + ] + }, + { + "key": [ + "JUWELS", + "mem192" + ], + "value": [ + 1, + 64 + ] + }, + { + "key": [ + "JUWELS", + "devel" + ], + "value": [ + 1, + 8 + ] + }, + { + "key": [ + "JUWELS", + "gpus" + ], + "value": [ + 1, + 46 + ] + }, + { + "key": [ + "JUWELS", + "develgpus" + ], + "value": [ + 1, + 2 + ] + }, + { + "key": [ + "JUWELS", + "booster" + ], + "value": [ + 1, + 384 + ] + }, + { + "key": [ + "JUWELS", + "develbooster" + ], + "value": [ + 1, + 4 + ] + }, + { + "key": [ + "LUMI", + "standard-g" + ], + "value": [ + 1, + 1024 + ] + }, + { + "key": [ + "LUMI", + "standard" + ], + "value": [ + 1, + 512 + ] + }, + { + "key": [ + "LUMI", + "dev-g" + ], + "value": [ + 1, + 32 + ] + }, + { + "key": [ + "LUMI", + "debug" + ], + "value": [ + 1, + 4 + ] + }, + { + "key": [ + "LUMI", + "small-g" + ], + "value": [ + 1, + 4 + ] + }, + { + "key": [ + "LUMI", + "small" + ], + "value": [ + 1, + 4 + ] + }, + { + "key": [ + "LUMI", + "largemem" + ], + "value": [ + 1, + 1 + ] + }, + { + "key": [ + "JURECA", + "dc-cpu" + ], + "value": [ + 1, + 128 + ] + }, + { + "key": [ + "JURECA", + "dc-cpu-bigmem" + ], + "value": [ + 1, + 48 + ] + }, + { + "key": [ + "JURECA", + "dc-cpu-devel" + ], + "value": [ + 1, + 4 + ] + }, + { + "key": [ + "JURECA", + "dc-gpu" + ], + "value": [ + 1, + 24 + ] + }, + { + "key": [ + "JURECA", + "dc-gpu-devel" + ], + "value": [ + 1, + 4 + ] + }, + { + "key": [ + "DEEP", + "dp-esb" + ], + "value": [ + 1, + 75 + ] + }, + { + "key": [ + "DEEP", + "dp-dam" + ], + "value": [ + 1, + 16 + ] + } + ] + } + } + } + }, + { + "name": "account", + "desc": "Specify the account for your job.", + "type": "string", + "default": "Account", + "scope": [ + { + "fields": [ + "system", + "software" + ], + "values": [ + [ + "VEGA", + "Basilisk" + ], + [ + "MockHPCSystem", + "MockSoftware" + ], + [ + "Cyclone", + "Basilisk" + ], + [ + "Cyclone", + "Horovod" + ], + [ + "JUWELS", + "HeAT" + ], + [ + "JUWELS", + "Horovod" + ], + [ + "JUWELS", + "Pytorch-DDP" + ], + [ + "JUWELS", + "DeepSpeed" + ], + [ + "LUMI", + "HeAT" + ], + [ + "JURECA", + "HeAT" + ], + [ + "JURECA", + "Horovod" + ], + [ + "JURECA", + "Pytorch-DDP" + ], + [ + "JURECA", + "DeepSpeed" + ], + [ + "DEEP", + "HeAT" + ], + [ + "DEEP", + "Horovod" + ], + [ + "DEEP", + "Pytorch-DDP" + ], + [ + "DEEP", + "DeepSpeed" + ] + ] + } + ] + }, + { + "name": "executable", + "desc": "Specify an executable for your job.", + "type": "string", + "default": "app", + "scope": [ + { + "fields": [ + "system", + "software" + ], + "values": [ + [ + "VEGA", + "Basilisk" + ], + [ + "MockHPCSystem", + "MockSoftware" + ], + [ + "Cyclone", + "Basilisk" + ], + [ + "Cyclone", + "Horovod" + ], + [ + "JUWELS", + "HeAT" + ], + [ + "JUWELS", + "Horovod" + ], + [ + "JUWELS", + "Pytorch-DDP" + ], + [ + "JUWELS", + "DeepSpeed" + ], + [ + "LUMI", + "HeAT" + ], + [ + "JURECA", + "HeAT" + ], + [ + "JURECA", + "Horovod" + ], + [ + "JURECA", + "Pytorch-DDP" + ], + [ + "JURECA", + "DeepSpeed" + ], + [ + "DEEP", + "HeAT" + ], + [ + "DEEP", + "Horovod" + ], + [ + "DEEP", + "Pytorch-DDP" + ], + [ + "DEEP", + "DeepSpeed" + ] + ] + } + ] + } + ], + "documentation": { + "system": { + "JURECA": "https://apps.fz-juelich.de/jsc/hps/jureca/index.html", + "DEEP": "https://deeptrac.zam.kfa-juelich.de:8443/trac/wiki/Public/User_Guide", + "JUWELS": "https://apps.fz-juelich.de/jsc/hps/juwels/index.html", + "LUMI": "https://docs.lumi-supercomputer.eu/software/", + "VEGA": "https://doc.vega.izum.si", + "Cyclone": "https://hpcf.cyi.ac.cy/documentation/" + }, + "software": { + "Pytorch-DDP": "https://pytorch.org/tutorials/intermediate/ddp_tutorial.html", + "Horovod": "https://horovod.readthedocs.io/en/stable/", + "DeepSpeed": "https://deepspeed.readthedocs.io/en/latest/", + "HeAT": "https://heat.readthedocs.io/en/stable/" + } + } +} \ No newline at end of file diff --git a/data/form-schema.json_ b/data/form-schema.json_ new file mode 100644 index 0000000000000000000000000000000000000000..1cb083290b6440cc3bfc8864319069f00badd255 --- /dev/null +++ b/data/form-schema.json_ @@ -0,0 +1,747 @@ +{ + "fields": [ + { + "name": "system", + "desc": "Select the computing system on which you want to submit your job.", + "type": "string", + "restriction": { + "type": "option", + "value": [ + "Cyclone", + "DEEP", + "JURECA", + "JUWELS", + "LUMI", + "MockHPCSystem", + "VEGA" + ] + } + }, + { + "name": "software", + "desc": "Select the software your job depends on.", + "type": "string", + "restriction": { + "type": "option", + "value": { + "depends_on": { + "fields": [ + "system" + ], + "resolution": [ + { + "key": [ + "VEGA" + ], + "value": [ + "Basilisk" + ] + }, + { + "key": [ + "MockHPCSystem" + ], + "value": [ + "MockSoftware" + ] + }, + { + "key": [ + "Cyclone" + ], + "value": [ + "Basilisk", + "Horovod" + ] + }, + { + "key": [ + "JUWELS" + ], + "value": [ + "HeAT", + "Horovod", + "Pytorch-DDP", + "DeepSpeed" + ] + }, + { + "key": [ + "LUMI" + ], + "value": [ + "HeAT", + "Pytorch-DDP" + ] + }, + { + "key": [ + "JURECA" + ], + "value": [ + "HeAT", + "Horovod", + "Pytorch-DDP", + "DeepSpeed" + ] + }, + { + "key": [ + "DEEP" + ], + "value": [ + "HeAT", + "Horovod", + "Pytorch-DDP", + "DeepSpeed" + ] + } + ] + } + } + } + }, + { + "name": "partition", + "desc": "Select the partition for your job.", + "type": "string", + "restriction": { + "type": "option", + "value": { + "depends_on": { + "fields": [ + "system" + ], + "resolution": [ + { + "key": [ + "VEGA" + ], + "value": [ + "dev", + "cpu", + "longcpu", + "gpu", + "largemem" + ] + }, + { + "key": [ + "MockHPCSystem" + ], + "value": [ + "base" + ] + }, + { + "key": [ + "Cyclone" + ], + "value": [ + "milan", + "skylake", + "nehalem", + "cpu", + "p100", + "a100", + "gpu" + ] + }, + { + "key": [ + "JUWELS" + ], + "value": [ + "batch", + "mem192", + "devel", + "gpus", + "develgpus", + "booster", + "develbooster" + ] + }, + { + "key": [ + "LUMI" + ], + "value": [ + "standard-g", + "standard", + "dev-g", + "debug", + "small-g", + "small", + "largemem" + ] + }, + { + "key": [ + "JURECA" + ], + "value": [ + "dc-cpu", + "dc-cpu-bigmem", + "dc-cpu-devel", + "dc-gpu", + "dc-gpu-devel" + ] + }, + { + "key": [ + "DEEP" + ], + "value": [ + "dp-esb", + "dp-dam" + ] + } + ] + } + } + } + }, + { + "name": "nodes", + "desc": "Select the number of nodes.", + "type": "number", + "restriction": { + "type": "range", + "value": { + "depends_on": { + "fields": [ + "system", + "partition" + ], + "resolution": [ + { + "key": [ + "VEGA", + "dev" + ], + "value": [ + 1, + 8 + ] + }, + { + "key": [ + "VEGA", + "cpu" + ], + "value": [ + 1, + 960 + ] + }, + { + "key": [ + "VEGA", + "longcpu" + ], + "value": [ + 1, + 6 + ] + }, + { + "key": [ + "VEGA", + "gpu" + ], + "value": [ + 1, + 60 + ] + }, + { + "key": [ + "VEGA", + "largemem" + ], + "value": [ + 1, + 192 + ] + }, + { + "key": [ + "MockHPCSystem", + "base" + ], + "value": [ + 1, + 10 + ] + }, + { + "key": [ + "Cyclone", + "milan" + ], + "value": [ + 1, + 34 + ] + }, + { + "key": [ + "Cyclone", + "skylake" + ], + "value": [ + 1, + 3 + ] + }, + { + "key": [ + "Cyclone", + "nehalem" + ], + "value": [ + 1, + 3 + ] + }, + { + "key": [ + "Cyclone", + "cpu" + ], + "value": [ + 1, + 13 + ] + }, + { + "key": [ + "Cyclone", + "p100" + ], + "value": [ + 1, + 8 + ] + }, + { + "key": [ + "Cyclone", + "a100" + ], + "value": [ + 1, + 6 + ] + }, + { + "key": [ + "Cyclone", + "gpu" + ], + "value": [ + 1, + 16 + ] + }, + { + "key": [ + "JUWELS", + "batch" + ], + "value": [ + 1, + 1024 + ] + }, + { + "key": [ + "JUWELS", + "mem192" + ], + "value": [ + 1, + 64 + ] + }, + { + "key": [ + "JUWELS", + "devel" + ], + "value": [ + 1, + 8 + ] + }, + { + "key": [ + "JUWELS", + "gpus" + ], + "value": [ + 1, + 46 + ] + }, + { + "key": [ + "JUWELS", + "develgpus" + ], + "value": [ + 1, + 2 + ] + }, + { + "key": [ + "JUWELS", + "booster" + ], + "value": [ + 1, + 384 + ] + }, + { + "key": [ + "JUWELS", + "develbooster" + ], + "value": [ + 1, + 4 + ] + }, + { + "key": [ + "LUMI", + "standard-g" + ], + "value": [ + 1, + 1024 + ] + }, + { + "key": [ + "LUMI", + "standard" + ], + "value": [ + 1, + 512 + ] + }, + { + "key": [ + "LUMI", + "dev-g" + ], + "value": [ + 1, + 32 + ] + }, + { + "key": [ + "LUMI", + "debug" + ], + "value": [ + 1, + 4 + ] + }, + { + "key": [ + "LUMI", + "small-g" + ], + "value": [ + 1, + 4 + ] + }, + { + "key": [ + "LUMI", + "small" + ], + "value": [ + 1, + 4 + ] + }, + { + "key": [ + "LUMI", + "largemem" + ], + "value": [ + 1, + 1 + ] + }, + { + "key": [ + "JURECA", + "dc-cpu" + ], + "value": [ + 1, + 128 + ] + }, + { + "key": [ + "JURECA", + "dc-cpu-bigmem" + ], + "value": [ + 1, + 48 + ] + }, + { + "key": [ + "JURECA", + "dc-cpu-devel" + ], + "value": [ + 1, + 4 + ] + }, + { + "key": [ + "JURECA", + "dc-gpu" + ], + "value": [ + 1, + 24 + ] + }, + { + "key": [ + "JURECA", + "dc-gpu-devel" + ], + "value": [ + 1, + 4 + ] + }, + { + "key": [ + "DEEP", + "dp-esb" + ], + "value": [ + 1, + 75 + ] + }, + { + "key": [ + "DEEP", + "dp-dam" + ], + "value": [ + 1, + 16 + ] + } + ] + } + } + } + }, + { + "name": "account", + "desc": "Specify the account for your job.", + "type": "string", + "default": "Account", + "scope": [ + { + "fields": [ + "system", + "software" + ], + "values": [ + [ + "VEGA", + "Basilisk" + ], + [ + "MockHPCSystem", + "MockSoftware" + ], + [ + "Cyclone", + "Basilisk" + ], + [ + "Cyclone", + "Horovod" + ], + [ + "JUWELS", + "HeAT" + ], + [ + "JUWELS", + "Horovod" + ], + [ + "JUWELS", + "Pytorch-DDP" + ], + [ + "JUWELS", + "DeepSpeed" + ], + [ + "LUMI", + "HeAT" + ], + [ + "JURECA", + "HeAT" + ], + [ + "JURECA", + "Horovod" + ], + [ + "JURECA", + "Pytorch-DDP" + ], + [ + "JURECA", + "DeepSpeed" + ], + [ + "DEEP", + "HeAT" + ], + [ + "DEEP", + "Horovod" + ], + [ + "DEEP", + "Pytorch-DDP" + ], + [ + "DEEP", + "DeepSpeed" + ] + ] + } + ] + }, + { + "name": "executable", + "desc": "Specify an executable for your job.", + "type": "string", + "default": "app", + "scope": [ + { + "fields": [ + "system", + "software" + ], + "values": [ + [ + "VEGA", + "Basilisk" + ], + [ + "MockHPCSystem", + "MockSoftware" + ], + [ + "Cyclone", + "Basilisk" + ], + [ + "Cyclone", + "Horovod" + ], + [ + "JUWELS", + "HeAT" + ], + [ + "JUWELS", + "Horovod" + ], + [ + "JUWELS", + "Pytorch-DDP" + ], + [ + "JUWELS", + "DeepSpeed" + ], + [ + "LUMI", + "HeAT" + ], + [ + "JURECA", + "HeAT" + ], + [ + "JURECA", + "Horovod" + ], + [ + "JURECA", + "Pytorch-DDP" + ], + [ + "JURECA", + "DeepSpeed" + ], + [ + "DEEP", + "HeAT" + ], + [ + "DEEP", + "Horovod" + ], + [ + "DEEP", + "Pytorch-DDP" + ], + [ + "DEEP", + "DeepSpeed" + ] + ] + } + ] + } + ], + "documentation": { + "system": { + "JURECA": "https://apps.fz-juelich.de/jsc/hps/jureca/index.html", + "DEEP": "https://deeptrac.zam.kfa-juelich.de:8443/trac/wiki/Public/User_Guide", + "JUWELS": "https://apps.fz-juelich.de/jsc/hps/juwels/index.html", + "LUMI": "https://docs.lumi-supercomputer.eu/software/", + "VEGA": "https://doc.vega.izum.si", + "Cyclone": "https://hpcf.cyi.ac.cy/documentation/" + }, + "software": { + "Pytorch-DDP": "https://pytorch.org/tutorials/intermediate/ddp_tutorial.html", + "Horovod": "https://horovod.readthedocs.io/en/stable/", + "DeepSpeed": "https://deepspeed.readthedocs.io/en/latest/", + "HeAT": "https://heat.readthedocs.io/en/stable/" + } + } +} \ No newline at end of file diff --git a/data/status.json b/data/status.json new file mode 100644 index 0000000000000000000000000000000000000000..3d7e29e303179bb4b2c96fa84d6064706f91cf10 --- /dev/null +++ b/data/status.json @@ -0,0 +1,61 @@ +{ + "Cyclone": { + "Basilisk": { + }, + "Horovod": { + "passed": true + } + }, + "DEEP": { + "DeepSpeed": { + "passed": true + }, + "HeAT": { + "passed": true + }, + "Horovod": { + "passed": true + }, + "Pytorch-DDP": { + "passed": true + } + }, + "JUWELS": { + "DeepSpeed": { + "passed": true + }, + "HeAT": { + "passed": false + }, + "Horovod": { + "passed": true + }, + "Pytorch-DDP": { + "passed": true + } + }, + "JURECA": { + "DeepSpeed": { + "passed": true + }, + "HeAT": { + "passed": true + }, + "Horovod": { + "passed": true + }, + "Pytorch-DDP": { + "passed": true + } + }, + "LUMI": { + "Pytorch-DDP": { + "passed": true + } + }, + "VEGA": { + "Basilisk": { + "passed": true + } + } +} diff --git a/html/about.html b/html/about.html new file mode 100644 index 0000000000000000000000000000000000000000..5cdabba83e1e756bad5c840060f20649f60e7738 --- /dev/null +++ b/html/about.html @@ -0,0 +1,31 @@ +<h1 class="display-6 mt-4 mb-5 h-color"> + <b>L</b>oad + <b>A</b>I + <b>M</b>odules, + <b>E</b>nvironments & + <b>C</b>ontainers<br> +</h1> +<section> + <p>The <strong>LAMEC</strong> API ( + <b>L</b>oad + <b>A</b>I + <b>M</b>odules, + <b>E</b>nvironments and + <b>C</b>ontainers) + is a tool that allows HPC developers and researchers to share their + configurations, setups and jobscripts of commonly used frameworks + and libraries, so they can be used to generate up to date + jobscripts. Take a look at the + <a href="index.php">jobscript generator</a> on this site + to see what systems and software are available. If you want to + contribute or learn about the structure of the project, please + read the + <a href="https://gitlab.jsc.fz-juelich.de/CoE-RAISE/FZJ/lamec-oa/-/wikis/LAMEC-Project-Overview" target="_blank"> + wiki + </a> + in the GitLab + <a href="https://gitlab.jsc.fz-juelich.de/CoE-RAISE/FZJ/lamec-oa" target="_blank"> + repository. + </a> + </p> +</section> diff --git a/html/form.html b/html/form.html new file mode 100644 index 0000000000000000000000000000000000000000..da453fae8bdf8c078fa7bc606a6b8e178eaaad4a --- /dev/null +++ b/html/form.html @@ -0,0 +1,6 @@ +<form action="index.php", method="post"> + <div id="formFields"></div> + <button type="submit" name="Submit" class="btn btn-primary mt-5"> + Generate jobscript + </button> +</form> diff --git a/html/output.html b/html/output.html new file mode 100644 index 0000000000000000000000000000000000000000..01014a42f109d80c95e68f3c442b162999b8b25a --- /dev/null +++ b/html/output.html @@ -0,0 +1,4 @@ +<div class="mb-3"> + <label for="output" class="form-label"><b>Your start script:</b></label> + <textarea id="jobscript-output" rows="20" class="form-control"><?php echo $output ?></textarea> +</div> diff --git a/html/status.html b/html/status.html new file mode 100644 index 0000000000000000000000000000000000000000..793cba697c93c28c8d779ace111bbf6aa69f997c --- /dev/null +++ b/html/status.html @@ -0,0 +1,12 @@ +<table class="table table-striped table-bordered table-hover my-5"> + <thead> + <tr> + <th scope="col">System</th> + <th scope="col">Software</th> + <th scope="col">Status</th> + </tr> + </thead> + <tbody id="table-body"> + </tbody> +</table> + diff --git a/2021-01-Logo-RGB-RAISE_standard.png b/images/logo.png similarity index 100% rename from 2021-01-Logo-RGB-RAISE_standard.png rename to images/logo.png diff --git a/index.php b/index.php index 143a6a8957018bd6e9068175492a81d43404d78d..97e4c9cfcb2991653ff7bcab2427f53a36ebefa2 100644 --- a/index.php +++ b/index.php @@ -1,416 +1,32 @@ <?php - // For testing purposes, output all PHP errors - ini_set('display_errors', 1); - ini_set('display_startup_errors', 1); - error_reporting(E_ALL); - - // - // Read configuration data from JSON file - // (TBD get output from LAMEC) - // - $filename = "form_schema.json"; - $config_json = file_get_contents($filename); - // Remove line breaks so the JSON can be embedded as a string in the JS code - $config_json_str = json_encode($config_json); +include 'render.php'; + +if(isset( $_POST['Submit'])) { + // Convert JSON confid settings to array + // $config = json_decode($config_json, true); + // Can be used if user input has to be verified + + // + // Create JSON payload to pass on to LAMEC + // + $payload = array(); + foreach($_POST as $key => $val) { + if($val != "") { + $payload[$key] = $val; + } + } + $json_payload = json_encode($payload); + + // putenv('PYTHONPATH="/var/www/apps/jsc/lamec"'); + $Phrase = "./lamec.py '$json_payload'"; + // $command = escapeshellcmd($Phrase); + $output = shell_exec($Phrase); + $active = 'form'; + $content = loadFragment('html/output.html', ['output' => $output]); + include 'base.php'; +} else { + $active = 'form'; + $content = loadFragment('html/form.html'); + include 'base.php'; +} ?> -<!doctype html> -<html> -<head> - <meta charset="utf-8"> - <meta name="viewport" content="width=device-width, initial-scale=1"> - <title>Load AI Modules, Environments, and Containers (LAMEC) API</title> - <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-9ndCyUaIbzAi2FUVXJi0CjmCapSmO7SnpJef0486qhLnuZ2cdeRhO02iuK6FUUVM" crossorigin="anonymous"> - <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js" integrity="sha384-geWF76RCwLtnZ8qwWowPQNguL3RmwHVBC9FhGdlKrxdiJJigb/j/68SIy3Te4Bkz" crossorigin="anonymous"></script> - <script src="https://code.jquery.com/jquery-3.7.1.min.js" integrity="sha256-/JqT3SQfawRcv/BIHPThkBvs0OEvtFFmqPF/lYI/Cxo=" crossorigin="anonymous"></script> - - <script> - window.onload = function() { - // All configuration settings from LAMEC - var json_config = JSON.parse(<?=$config_json_str?>); - - // Default html container name for fields - defaultFieldPosition = $("#formFields") - - // - // Set up the form dynamically with all fields from the - // LAMEC configuration - // - $.each(json_config.fields, function(key, field) { - // - // Add the header for the field, containing the field name - // and a description of the field - // - addFieldHeaderElement(field.name, field.desc); - - // - // Add an empty field element as specified in the JSON data. - // Check for the special case where field type is string, but there is - // a restriction of type 'option', in that case the field is SELECT. - // - fieldType = field.type; - if(fieldType == 'string' && field.restriction && field.restriction.type == 'option') { - fieldType = 'select'; - } - addFieldElement(field.name, fieldType); - - // - // Process the settings for the field that was created above and add - // the settings as a data attribute to each form field for later use. - // - if(field.restriction) { - $("#" + field.name).data("restriction", field.restriction); - } - if(field.scope) { - $("#" + field.name).data("scope", field.scope); - } - if(field.default) { - $("#" + field.name).data("default", field.default); - } - - // - // Check if there is documentation available for this field, and if there is then - // add it as a data attribute to the relevant form field for later reference, - // then add the html element. - // - if(json_config.documentation && json_config.documentation[field.name]) { - $("#" + field.name).data("documentation", json_config.documentation[field.name]); - addDocumentationElement(field.name); - } - - // - // Process this field's data and update the form element accordingly, - // taking into account all restrictions, dependencies and scope. - // - setFieldAttributes(field.name); - }); - - - // - // Adds the html header for a field. - // - function addFieldHeaderElement(fieldName, fieldDescription, fieldPosition = defaultFieldPosition) { - new_field = '<div class="mt-4" '; - new_field += 'id="' + fieldName + 'Header" '; - new_field += '><label for="'; - new_field += fieldName; - new_field += '" class="form-label"><b>'; - new_field += fieldName[0].toUpperCase() + fieldName.slice(1).replace(/_/g, ' '); - new_field += '</b></label><div id="'; - new_field += fieldName; - new_field += 'Help" class="form-text mt-0 mb-1">'; - new_field += fieldDescription; - new_field += '</div></div>'; - fieldPosition.append(new_field); - } - - // - // Adds an empty field element. - // - function addFieldElement(fieldName, fieldType, fieldPosition = defaultFieldPosition) { - new_field = '<div class="my-0" '; - new_field += 'id="' + fieldName + 'Element">'; - if(fieldType == 'select') { - new_field += '<select class="form-select" '; - } - else if(fieldType == 'number') { - new_field += '<input class="form-control" type="number" '; - } - else if(fieldType == 'string') { - new_field += '<input class="form-control" type="text" '; - } - - new_field += 'id="' + fieldName + '" '; - new_field += 'name="' + fieldName + '" '; - new_field += 'aria-describedby="' + fieldName + 'Help" >'; - - if(fieldType == 'select') { - new_field += '</select>'; - } - new_field += '</div>'; - fieldPosition.append(new_field); - } - - // - // Add an html documentation element. - // - function addDocumentationElement(fieldName, fieldPosition = defaultFieldPosition) { - new_field = '<div class="mt-1 mb-0" id="' + fieldName + '-documentation">'; - new_field += '<small class="text-body-secondary">'; - new_field += '<span id="' + fieldName + '-name"></span> '; - new_field += '<a id="' + fieldName + '-documentation-url" href="#" target="_blank">documentation</a> '; - new_field += '<svg xmlns="http://www.w3.org/2000/svg" width="12" height="12" fill="currentColor" class="bi bi-box-arrow-up-right" viewBox="0 0 16 16">'; - new_field += '<path fill-rule="evenodd" d="M8.636 3.5a.5.5 0 0 0-.5-.5H1.5A1.5 1.5 0 0 0 0 4.5v10A1.5 1.5 0 0 0 1.5 16h10a1.5 1.5 0 0 0 1.5-1.5V7.864a.5.5 0 0 0-1 0V14.5a.5.5 0 0 1-.5.5h-10a.5.5 0 0 1-.5-.5v-10a.5.5 0 0 1 .5-.5h6.636a.5.5 0 0 0 .5-.5z"/>'; - new_field += '<path fill-rule="evenodd" d="M16 .5a.5.5 0 0 0-.5-.5h-5a.5.5 0 0 0 0 1h3.793L6.146 9.146a.5.5 0 1 0 .708.708L15 1.707V5.5a.5.5 0 0 0 1 0v-5z"/>'; - new_field += '</svg></small></div>'; - fieldPosition.append(new_field); - } - - // - // Process the field's data and update the form element accordingly, - // taking into account all restrictions, dependencies and scope. - // - function setFieldAttributes(fieldName) { - fieldElement = $("#" + fieldName); - - if(fieldElement.data("scope")) { - // - // The field has a specific scope, show or hide - // the field accordingly. - // - if(isFieldWithinScope(fieldElement.data("scope"))) { - $("#" + fieldName + "Header").show(); - $("#" + fieldName + "Element").show(); - } - else { - $("#" + fieldName + "Header").hide(); - $("#" + fieldName + "Element").hide(); - } - } - - restriction = fieldElement.data("restriction"); - if(restriction) { - // - // Process the field's restrictions. - // - restrictionType = restriction.type; - - // - // The field is a select field, delete all options present - // and then repopulate the field, taking into account restrictions - // and dependencies. - // - if(restrictionType == 'option') { - $("#" + fieldName).length = 0; - } - - if(restriction.value.depends_on) { - dependantFields = restriction.value.depends_on.fields; - dependantResolution = restriction.value.depends_on.resolution; - - $.each(dependantResolution, function(index, resolution) { - // Track the number of resolutions that are met - resolutionCount = 0; - for(i=0; i<resolution.key.length; i++) { - if(resolution.key[i] == document.getElementById(dependantFields[i]).value) { - // one resolution met - resolutionCount++; - } - else { - // a resolution not met, skip to next - // continue - return(true); - } - } - - if(resolutionCount == i) { - // All dependant resolutions met - if(restrictionType == 'range') { - fieldElement.attr("min", resolution.value[0]); - fieldElement.attr("max", resolution.value[1]); - fieldElement.val(resolution.value[0]); - } - else if(restrictionType == 'option') { - populateFieldElementOptions(fieldName, resolution.value); - } - // As all resolutions were met, no need to search further. - // break - return(false); - } - }); - } - else { - if(restrictionType == 'option') { - populateFieldElementOptions(fieldName, restriction.value); - } - else if (restrictionType == 'range'){ - fieldElement.attr("min", restriction.value[0]); - fieldElement.attr("max", restriction.value[1]); - fieldElement.val(restriction.value[0]); - } - } - } - - // Set defaut field value, if defined. - if(fieldElement.data("default")) { - fieldElement.val(fieldElement.data("default")); - } - - if(fieldElement.data("documentation")) { - // Show documentation if selected option has documentation available - updateDocumentation(fieldName); - } - } - - // - // Method to update link to documentation for selected option - // - function updateDocumentation(fieldName) { - let documentationFound = false; - $.each($("#" + fieldName).data("documentation"), function(key, val) { - if(document.getElementById(fieldName).value == key) { - $("#" + fieldName + "-name").text(key); - $("#" + fieldName + "-documentation-url").attr("href", val); - documentationFound = true; - // break - return(false); - } - }); - if(documentationFound) { - $("#" + fieldName + "-documentation").show(); - } - else { - $("#" + fieldName + "-documentation").hide(); - } - } - - // - // Method to pupolate the options of a select element - // - function populateFieldElementOptions(fieldName, fieldValues) { - sel_element = document.getElementById(fieldName); - sel_element.length = 0; - $.each(fieldValues, function(key, val) { - sel_element.options[sel_element.options.length] = new Option(val, val); - }); - } - - // - // Method to check if a field is within scope. - // - function isFieldWithinScope(fieldScope) { - let isWithinScope = false; - if(fieldScope) { - $.each(fieldScope, function(key, scope) { - $.each(scope.values, function(key, vals) { - let matchedVals = 0; - for(i = 0; i < vals.length; i++) { - if(vals[i] == document.getElementById(scope.fields[i]).value) { - matchedVals++; - } - else { - continue; - } - } - if(matchedVals == vals.length) { - isWithinScope = true; - return(false); - } - }) - }); - return(isWithinScope); - } - return(false); - } - - // - // Catch all changes to select elements and update other fields accordingly, - // based on the rules of dependencies, scope and available documentation - // - $(".form-select").on('change', function() { - changedField = this.name; - - // If field has documentation data, then it needs updating - if($("#" + changedField).data("documentation")) { - updateDocumentation(changedField); - } - - $.each(json_config.fields, function(key, field) { - if(field.scope) { - setFieldAttributes(field.name); - } - else if(field.restriction && field.restriction.value && field.restriction.value.depends_on) { - $.each(field.restriction.value.depends_on.fields, function(key, val) { - if(val == changedField) { - // Update the field, according to set dependencies - setFieldAttributes(field.name); - } - }); - } - }); - - }); - } - </script> - <style> - .form-control::placeholder { - color: var(--bs-dark-bg-subtle); - } - </style> -</head> -<body> - <nav class="navbar"> - <div class="container justify-content-center mt-3"> - <a class="navbar-brand" href="https://www.coe-raise.eu"> - <img src="/2021-01-Logo-RGB-RAISE_standard.png" - height="160" - alt="RAISE Logo" - loading="lazy" /> - </a> - </div> - </nav> - <div class="container my-5" style="max-width: 980px;"> - <div class="container justify-content-center"> - <h1 class="display-6" style="text-align:center; color: rgb(4,132,196);">Load AI Modules, Environments, and Containers (LAMEC) API</h1> - </div> - <br><br> - <?php - if(isset( $_POST['Submit'])) { - // Convert JSON confid settings to array - // $config = json_decode($config_json, true); - // Can be used if user input has to be verified - - - // - // Create JSON payload to pass on to LAMEC - // - $payload = array(); - foreach($_POST as $key => $val) { - if($val != "") { - $payload[$key] = $val; - } - } - $json_payload = json_encode($payload); - - // putenv('PYTHONPATH="/var/www/apps/jsc/lamec"'); - $Phrase = "./lamec.py '$json_payload'"; - // $command = escapeshellcmd($Phrase); - $output = shell_exec($Phrase); - ?> - <div class="mb-3"> - <label for="output" class="form-label"><b>Your start script:</b></label> - <textarea rows="20" class="form-control"><?=$output?></textarea> - </div> - <?php - } - else { - ?> - <form action="index.php", method="post"> - <div id="formFields"></div> - <button type="submit" name="Submit" class="btn btn-primary mt-5">Create start script</button> - </form> - <?php - } - ?> - <br> - </div> - <div class="container-fluid" style="background-color: rgb(158,196,243);"> - <div class="container justify-content-center" style="max-width: 980px; text-align:center;"> - <!-- If we want to show the menu links in the footer... - <ul class="nav justify-content-center pt-1 pb-3 mb-3"> - <li class="nav-item px-4"> - <a href="https://www.coe-raise.eu/contact" class="nav-link text-body-secondary">Contact</a> - </li> - <li class="nav-item px-4"> - <a href="https://www.coe-raise.eu/imprint" class="nav-link text-body-secondary">Imprint</a> - </li> - <li class="nav-item px-4"> - <a href="https://www.coe-raise.eu/privacy-policy" class="nav-link text-body-secondary">Privacy Policy</a> - </li> - </ul> - --> - <div class="py-3">The CoE RAISE project have received funding from the European Union’s Horizon 2020 – Research and Innovation Framework Programme H2020-INFRAEDI-2019-1 under grant agreement no. 951733</div> - <div class="py-2">©2021 CoE RAISE.</div> - </div> - </div> -</body> -</html> diff --git a/js/form.js b/js/form.js new file mode 100644 index 0000000000000000000000000000000000000000..d255bc3e583e31360ab224a786de50edb8eb3350 --- /dev/null +++ b/js/form.js @@ -0,0 +1,307 @@ +window.addEventListener("load", (event) => { + $.getJSON("data/form-schema.json", init); +}); + +function init(json_config) { + // Default html container name for fields + defaultFieldPosition = $("#formFields") + + // + // Set up the form dynamically with all fields from the + // LAMEC configuration + // + $.each(json_config.fields, function(key, field) { + // + // Add the header for the field, containing the field name + // and a description of the field + // + addFieldHeaderElement(field.name, field.desc); + + // + // Add an empty field element as specified in the JSON data. + // Check for the special case where field type is string, but there is + // a restriction of type 'option', in that case the field is SELECT. + // + fieldType = field.type; + if(fieldType == 'string' && field.restriction && field.restriction.type == 'option') { + fieldType = 'select'; + } + addFieldElement(field.name, fieldType); + + // + // Process the settings for the field that was created above and add + // the settings as a data attribute to each form field for later use. + // + if(field.restriction) { + $("#" + field.name).data("restriction", field.restriction); + } + if(field.scope) { + $("#" + field.name).data("scope", field.scope); + } + if(field.default) { + $("#" + field.name).data("default", field.default); + } + + // + // Check if there is documentation available for this field, and if there is then + // add it as a data attribute to the relevant form field for later reference, + // then add the html element. + // + if(json_config.documentation && json_config.documentation[field.name]) { + $("#" + field.name).data("documentation", json_config.documentation[field.name]); + addDocumentationElement(field.name); + } + + // + // Process this field's data and update the form element accordingly, + // taking into account all restrictions, dependencies and scope. + // + setFieldAttributes(field.name); + }); + + + // + // Adds the html header for a field. + // + function addFieldHeaderElement(fieldName, fieldDescription, fieldPosition = defaultFieldPosition) { + new_field = '<div class="mt-4" '; + new_field += 'id="' + fieldName + 'Header" '; + new_field += '><label for="'; + new_field += fieldName; + new_field += '" class="form-label"><b>'; + new_field += fieldName[0].toUpperCase() + fieldName.slice(1).replace(/_/g, ' '); + new_field += '</b></label><div id="'; + new_field += fieldName; + new_field += 'Help" class="form-text mt-0 mb-1">'; + new_field += fieldDescription; + new_field += '</div></div>'; + fieldPosition.append(new_field); + } + + // + // Adds an empty field element. + // + function addFieldElement(fieldName, fieldType, fieldPosition = defaultFieldPosition) { + new_field = '<div class="my-0" '; + new_field += 'id="' + fieldName + 'Element">'; + if(fieldType == 'select') { + new_field += '<select class="form-select" '; + } + else if(fieldType == 'number') { + new_field += '<input class="form-control" type="number" '; + } + else if(fieldType == 'string') { + new_field += '<input class="form-control" type="text" '; + } + + new_field += 'id="' + fieldName + '" '; + new_field += 'name="' + fieldName + '" '; + new_field += 'aria-describedby="' + fieldName + 'Help" >'; + + if(fieldType == 'select') { + new_field += '</select>'; + } + new_field += '</div>'; + fieldPosition.append(new_field); + } + + // + // Add an html documentation element. + // + function addDocumentationElement(fieldName, fieldPosition = defaultFieldPosition) { + new_field = '<div class="mt-1 mb-0" id="' + fieldName + '-documentation">'; + new_field += '<small class="text-body-secondary">'; + new_field += '<span id="' + fieldName + '-name"></span> '; + new_field += '<a id="' + fieldName + '-documentation-url" href="#" target="_blank">documentation</a> '; + new_field += '<svg xmlns="http://www.w3.org/2000/svg" width="12" height="12" fill="currentColor" class="bi bi-box-arrow-up-right" viewBox="0 0 16 16">'; + new_field += '<path fill-rule="evenodd" d="M8.636 3.5a.5.5 0 0 0-.5-.5H1.5A1.5 1.5 0 0 0 0 4.5v10A1.5 1.5 0 0 0 1.5 16h10a1.5 1.5 0 0 0 1.5-1.5V7.864a.5.5 0 0 0-1 0V14.5a.5.5 0 0 1-.5.5h-10a.5.5 0 0 1-.5-.5v-10a.5.5 0 0 1 .5-.5h6.636a.5.5 0 0 0 .5-.5z"/>'; + new_field += '<path fill-rule="evenodd" d="M16 .5a.5.5 0 0 0-.5-.5h-5a.5.5 0 0 0 0 1h3.793L6.146 9.146a.5.5 0 1 0 .708.708L15 1.707V5.5a.5.5 0 0 0 1 0v-5z"/>'; + new_field += '</svg></small></div>'; + fieldPosition.append(new_field); + } + + // + // Process the field's data and update the form element accordingly, + // taking into account all restrictions, dependencies and scope. + // + function setFieldAttributes(fieldName) { + fieldElement = $("#" + fieldName); + + if(fieldElement.data("scope")) { + // + // The field has a specific scope, show or hide + // the field accordingly. + // + if(isFieldWithinScope(fieldElement.data("scope"))) { + $("#" + fieldName + "Header").show(); + $("#" + fieldName + "Element").show(); + } + else { + $("#" + fieldName + "Header").hide(); + $("#" + fieldName + "Element").hide(); + } + } + + restriction = fieldElement.data("restriction"); + if(restriction) { + // + // Process the field's restrictions. + // + restrictionType = restriction.type; + + // + // The field is a select field, delete all options present + // and then repopulate the field, taking into account restrictions + // and dependencies. + // + if(restrictionType == 'option') { + $("#" + fieldName).length = 0; + } + + if(restriction.value.depends_on) { + dependantFields = restriction.value.depends_on.fields; + dependantResolution = restriction.value.depends_on.resolution; + + $.each(dependantResolution, function(index, resolution) { + // Track the number of resolutions that are met + resolutionCount = 0; + for(i=0; i<resolution.key.length; i++) { + if(resolution.key[i] == document.getElementById(dependantFields[i]).value) { + // one resolution met + resolutionCount++; + } + else { + // a resolution not met, skip to next + // continue + return(true); + } + } + + if(resolutionCount == i) { + // All dependant resolutions met + if(restrictionType == 'range') { + fieldElement.attr("min", resolution.value[0]); + fieldElement.attr("max", resolution.value[1]); + fieldElement.val(resolution.value[0]); + } + else if(restrictionType == 'option') { + populateFieldElementOptions(fieldName, resolution.value); + } + // As all resolutions were met, no need to search further. + // break + return(false); + } + }); + } + else { + if(restrictionType == 'option') { + populateFieldElementOptions(fieldName, restriction.value); + } + else if (restrictionType == 'range'){ + fieldElement.attr("min", restriction.value[0]); + fieldElement.attr("max", restriction.value[1]); + fieldElement.val(restriction.value[0]); + } + } + } + + // Set defaut field value, if defined. + if(fieldElement.data("default")) { + fieldElement.val(fieldElement.data("default")); + } + + if(fieldElement.data("documentation")) { + // Show documentation if selected option has documentation available + updateDocumentation(fieldName); + } + } + + // + // Method to update link to documentation for selected option + // + function updateDocumentation(fieldName) { + let documentationFound = false; + $.each($("#" + fieldName).data("documentation"), function(key, val) { + if(document.getElementById(fieldName).value == key) { + $("#" + fieldName + "-name").text(key); + $("#" + fieldName + "-documentation-url").attr("href", val); + documentationFound = true; + // break + return(false); + } + }); + if(documentationFound) { + $("#" + fieldName + "-documentation").show(); + } + else { + $("#" + fieldName + "-documentation").hide(); + } + } + + // + // Method to pupolate the options of a select element + // + function populateFieldElementOptions(fieldName, fieldValues) { + sel_element = document.getElementById(fieldName); + sel_element.length = 0; + $.each(fieldValues, function(key, val) { + sel_element.options[sel_element.options.length] = new Option(val, val); + }); + } + + // + // Method to check if a field is within scope. + // + function isFieldWithinScope(fieldScope) { + let isWithinScope = false; + if(fieldScope) { + $.each(fieldScope, function(key, scope) { + $.each(scope.values, function(key, vals) { + let matchedVals = 0; + for(i = 0; i < vals.length; i++) { + if(vals[i] == document.getElementById(scope.fields[i]).value) { + matchedVals++; + } + else { + continue; + } + } + if(matchedVals == vals.length) { + isWithinScope = true; + return(false); + } + }) + }); + return(isWithinScope); + } + return(false); + } + + // + // Catch all changes to select elements and update other fields accordingly, + // based on the rules of dependencies, scope and available documentation + // + $(".form-select").on('change', function() { + changedField = this.name; + + // If field has documentation data, then it needs updating + if($("#" + changedField).data("documentation")) { + updateDocumentation(changedField); + } + + $.each(json_config.fields, function(key, field) { + if(field.scope) { + setFieldAttributes(field.name); + } + else if(field.restriction && field.restriction.value && field.restriction.value.depends_on) { + $.each(field.restriction.value.depends_on.fields, function(key, val) { + if(val == changedField) { + // Update the field, according to set dependencies + setFieldAttributes(field.name); + } + }); + } + }); + + }); +} diff --git a/js/status.js b/js/status.js new file mode 100644 index 0000000000000000000000000000000000000000..370c6ee3d068eac3c1ec382aefa9ff40e77653d6 --- /dev/null +++ b/js/status.js @@ -0,0 +1,31 @@ +window.addEventListener("load", (event) => { + $.getJSON("/data/status.json", init); +}); + +function passedIcon(passed) { + if (passed !== undefined) { + var color = passed ? 'green' : 'red'; + } else { + var color = 'grey'; + } + return `<i class="fa fa-solid fa-circle" style="color: ${color}"></i>`; +} + +function addTableElement(tableBody, system, software, passed) { + tableBody.append(` + <tr> + <td>${system}</td> + <td>${software}</td> + <td>${passedIcon(passed)}</td> + </tr> + `); +} + +function init(data) { + let tableBody = $("#table-body"); + $.each(data, (system, software_list) => { + $.each(software_list, (software, value) => { + addTableElement(tableBody, system, software, value.passed); + }); + }); +} diff --git a/lamec.py b/lamec.py index 79884367d6f4c0ab3fd4af3d67b8192278f68e6d..dac68757cc6ee0bcbc4e351eb843574177aa16c8 100755 --- a/lamec.py +++ b/lamec.py @@ -5,9 +5,36 @@ import json import os import re import update +import http.client scriptpath = f'{sys.path[0]}/scripts' +def report(system, software, passed): + server = 'localhost:5000' + endpoint = '/data/status.json' + + data = { + 'system': system, + 'software': software, + 'passed': passed + } + + json_data = json.dumps(data) + + conn = http.client.HTTPConnection(server) + + headers = { + 'Content-type': 'application/json', + 'Content-length': str(len(json_data)) + } + + conn.request('POST', endpoint, body=json_data, headers=headers) + response = conn.getresponse() + response_data = response.read() + print(response_data) + + conn.close() + class Module: """ Global variables @@ -185,7 +212,7 @@ def main(): else: args = json.loads(sys.argv[1]) - path = os.path.join('scripts', f"{args['system']}/{args['software']}") + path = os.path.join(scriptpath, f"{args['system']}/{args['software']}") with open(os.path.join(path, 'lamec.json'), 'r') as f: config = json.load(f) if 'startscript' in config: diff --git a/render.php b/render.php new file mode 100644 index 0000000000000000000000000000000000000000..3672cb08657832522b6817c1beedb2bf79cc3588 --- /dev/null +++ b/render.php @@ -0,0 +1,8 @@ +<?php +function loadFragment($filename, $variables = []) { + extract($variables); + ob_start(); + include $filename; + return ob_get_clean(); +} +?> diff --git a/scripts/MockHPCSystem/MockSoftware/lamec.json b/scripts/MockHPCSystem/MockSoftware/lamec.json new file mode 100644 index 0000000000000000000000000000000000000000..e82ad0e6397cb35eafcaeb5bc6af3557b822686c --- /dev/null +++ b/scripts/MockHPCSystem/MockSoftware/lamec.json @@ -0,0 +1,3 @@ +{ + "template": "template.sh" +} diff --git a/scripts/MockHPCSystem/MockSoftware/template.sh b/scripts/MockHPCSystem/MockSoftware/template.sh new file mode 100644 index 0000000000000000000000000000000000000000..1e26e128706a05c7a3c7c88c5bf72d543b66fde2 --- /dev/null +++ b/scripts/MockHPCSystem/MockSoftware/template.sh @@ -0,0 +1,5 @@ +#SBATCH --account=%account% +#SBATCH --partition=%partition% +#SBATCH --nodes=%nodes% + +srun %executable% diff --git a/scripts/MockHPCSystem/sysinfo.json b/scripts/MockHPCSystem/sysinfo.json new file mode 100644 index 0000000000000000000000000000000000000000..84f3f5f4c6fbae2a54b0b4a200103cbfe0d18573 --- /dev/null +++ b/scripts/MockHPCSystem/sysinfo.json @@ -0,0 +1,7 @@ +{ + "partition": { + "base": { + "nodes": 10 + } + } +} diff --git a/status.php b/status.php new file mode 100644 index 0000000000000000000000000000000000000000..19a5637393f61e558db9e14584f9b906639dd922 --- /dev/null +++ b/status.php @@ -0,0 +1,25 @@ +<?php +if ($_SERVER['REQUEST_METHOD'] === 'POST') { + $raw_data = file_get_contents('php://input'); + $json_data = json_decode($raw_data, true); + $file = fopen('/data/status.json', 'r'); + $data = json_decode(fread($file, filesize('/data/status.json')), true); + if (array_key_exists($json_data['system'], $data)) { + if (array_key_exists($json_data['software'], + $data[$json_data['system']])) { + $data[$json_data['system']][$json_data['software']]['passed'] + = $json_data['passed']; + } + } + fclose($file); + + $file = fopen('/data/status.json', 'w'); + fwrite($file, json_encode($data, JSON_PRETTY_PRINT)); + fclose($file); +} else { + include 'render.php'; + $active = 'status'; + $content = loadFragment('html/status.html'); + include 'base.php'; +} +?> diff --git a/update.py b/update.py index 15bf44f031dad25a37e765e307238ec69205b077..ef338d9d3396af7bc28f308854fa968571977588 100644 --- a/update.py +++ b/update.py @@ -172,7 +172,7 @@ def update_all(): fields.append(get_free_variable(var, defs)) form_schema = {'fields': fields, 'documentation': info['docs']} set_scope(fields) - with open('form_schema.json', 'w') as out: + with open('data/form-schema.json', 'w') as out: json.dump(form_schema, out, indent=4) def main():