From: Ioakeim Samaras Date: Fri, 17 May 2019 12:23:59 +0000 (+0300) Subject: UI initial implementation. X-Git-Tag: 2.0.0~78^2 X-Git-Url: https://gerrit.akraino.org/r/gitweb?p=validation.git;a=commitdiff_plain;h=c5ad3fa5dcff60eb9108ed303806ff28b31a9c09 UI initial implementation. - A user can commit and be informed about submissions of blueprint validation requests. - Appropriate dockerfiles have been added for the UI and the required postgreSQL db. - .gitignore file has been updated - Integration with Jenkins completed - The URL of the result is retrieved and displayed - Multi-threading is now supported - Notification callback from Jenkins implemented - Results are retrieved from Nexus - Results are displayed - UI and postgreSQL docker projects support the makefile automation build and push process - README file is included - CHANGELOG file is included - Coala static code analysis was performed JIRA: VAL-14 Signed-off-by: Ioakeim Samaras Change-Id: Icd2a97426bfbfc6e4eb4ec5edbda6689e2d4645f --- diff --git a/.coafile b/.coafile index 6896103..95a31b4 100644 --- a/.coafile +++ b/.coafile @@ -27,6 +27,7 @@ bears = ShellCheckBear,SpaceConsistencyBear files = **.sh shell = bash use_spaces = true +ignore = pmd-bin-6.15.0/** [all.YAML] bears = YAMLLintBear @@ -39,3 +40,19 @@ ignore = tests/k8s/conformance/sonobuoy.yaml bears = PyLintBear files = **.py use_spaces = true + +[all.Java] +bears = SpaceConsistencyBear,JavaPMDBear +files = ui/**.java +language = java +use_spaces = true + +[all.JS] +bears = ESLintBear,JSComplexityBear +files = ui/**.js +language = javascript +javascript_strictness = False +use_spaces = true +ignore = ui/src/main/webapp/reusable_chart.js, + ui/bin/**, + ui/target/** diff --git a/.gitignore b/.gitignore index 59230bc..fca7ab9 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,50 @@ docker/manifest-tool *.sw? + +# Compiled class files +*.class + +# Maven +**/target/ +pom.xml.tag +pom.xml.releaseBackup +pom.xml.versionsBackup +pom.xml.next +release.properties +dependency-reduced-pom.xml +buildNumber.properties +.mvn/timing.properties +# Avoid ignoring Maven wrapper jar file (.jar files are usually ignored) +!/.mvn/wrapper/maven-wrapper.jar +bin/ + +# Log file +*.log + +# BlueJ files +*.ctxt + +# Mobile Tools for Java (J2ME) +.mtj.tmp/ + +# Package Files +*.jar +*.war +*.nar +*.ear +*.zip +*.tar.gz +*.rar + +# IDE files +/.settings/ +.classpath +.project +.idea +*~ + +.* +!/.gitignore +!/.coafile +!/ui/src/main/webapp/.eslintrc + diff --git a/docker/README.rst b/docker/README.rst index 456354f..3a979af 100644 --- a/docker/README.rst +++ b/docker/README.rst @@ -75,3 +75,61 @@ stored on the local server. By default, the container will run the k8s conformance test. If you want to enter the container, add */bin/sh* at the end of the command above + + +The postgresql container +================= + +Building and pushing the container +---------------------------------- + +To build just the postgresql container, use the command: + +.. code-block:: console + + make postgresql-build [ REGISTRY= NAME=] + +To both build and push the container, use the command: + +.. code-block:: console + + make postgresql [ REGISTRY= NAME=] + +Using the container +------------------- +If you want to deploy the container, you can run the corresponding deploy.sh script with the appropriate parameters. + +Example: + +.. code-block:: console + ./deploy.sh POSTGRES_PASSWORD=password + + +The ui container +================= + +Building and pushing the container +---------------------------------- + +To build just the ui container, you must first compile the ui project. +Then use the command: + +.. code-block:: console + + make ui-build [ REGISTRY= NAME=] + +To both build and push the container, use the command: + +.. code-block:: console + + make ui [ REGISTRY= NAME=] + +Using the container +------------------- +If you want to deploy the container, you can run the corresponding deploy.sh script with the appropriate parameters. +Note, that you must also build and run the postgresql container for a functional UI. + +Example: + +.. code-block:: console + ./deploy.sh postgres_db_user_pwd=password jenkins_url=http://192.168.2.2:8080 jenkins_user_name=name jenkins_user_pwd=jenkins_pwd jenkins_job_name=job1 nexus_results_url=https://nexus.akraino.org/content/sites/logs proxy_ip=172.28.40.9 proxy_port=3128 diff --git a/docker/postgresql/Dockerfile b/docker/postgresql/Dockerfile new file mode 100644 index 0000000..0259da2 --- /dev/null +++ b/docker/postgresql/Dockerfile @@ -0,0 +1,21 @@ +############################################################################## +# Copyright (c) 2019 AT&T Intellectual Property. All rights reserved. # +# # +# Licensed under the Apache License, Version 2.0 (the "License"); # +# you maynot use this file except in compliance with the License. # +# # +# You may obtain a copy of the License at # +# http://www.apache.org/licenses/LICENSE-2.0 # +# # +# Unless required by applicable law or agreed to in writing, software # +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT # +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # +# See the License for the specific language governing permissions and # +# limitations under the License. # +############################################################################## + +FROM postgres:9.6.9 + +COPY akraino-blueprint_validation_db.sql /akraino-blueprint_validation_db.sql +RUN chown -R postgres:postgres /var/lib/postgresql/data && \ + chown -R postgres:postgres /akraino-blueprint_validation_db.sql \ No newline at end of file diff --git a/docker/postgresql/Makefile b/docker/postgresql/Makefile new file mode 100644 index 0000000..db91c1e --- /dev/null +++ b/docker/postgresql/Makefile @@ -0,0 +1,23 @@ +############################################################################## +# Copyright (c) 2019 AT&T Intellectual Property. All rights reserved. # +# # +# Licensed under the Apache License, Version 2.0 (the "License"); # +# you maynot use this file except in compliance with the License. # +# # +# You may obtain a copy of the License at # +# http://www.apache.org/licenses/LICENSE-2.0 # +# # +# Unless required by applicable law or agreed to in writing, software # +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT # +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # +# See the License for the specific language governing permissions and # +# limitations under the License. # +############################################################################## + +.PHONY: all +all: .push_image .push_manifest + +.PHONY: build +build: .build + +include ../build.mk diff --git a/docker/postgresql/akraino-blueprint_validation_db.sql b/docker/postgresql/akraino-blueprint_validation_db.sql new file mode 100644 index 0000000..fb27ad5 --- /dev/null +++ b/docker/postgresql/akraino-blueprint_validation_db.sql @@ -0,0 +1,127 @@ +/* + * Copyright (c) 2019 AT&T Intellectual Property. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +drop sequence IF EXISTS akraino.seq_timeslot; +drop sequence IF EXISTS akraino.seq_blueprint; +drop sequence IF EXISTS akraino.seq_blueprint_instance; +drop sequence IF EXISTS akraino.seq_submission; + +drop table IF EXISTS akraino.submission; +drop table IF EXISTS akraino.blueprint_instance; +drop table IF EXISTS akraino.blueprint; +drop table IF EXISTS akraino.timeslot; + +CREATE SCHEMA IF NOT EXISTS akraino + AUTHORIZATION postgres; + +CREATE TABLE akraino.timeslot +( + timeslot_id bigint not NULL unique, + start_date_time text not NULL, + duration int not NULL, + lab text not NULL +) +WITH ( + OIDS = FALSE +) +; +ALTER TABLE akraino.timeslot + OWNER TO postgres; + +CREATE TABLE akraino.blueprint +( + blueprint_id bigint not NULL, + blueprint_name text not NULL unique, + CONSTRAINT blueprint_id_pk PRIMARY KEY (blueprint_id) +) +WITH ( + OIDS = FALSE +) +; +ALTER TABLE akraino.blueprint + OWNER TO postgres; + +CREATE TABLE akraino.blueprint_instance +( + blueprint_instance_id bigint not NULL, + blueprint_id bigint not NULL, + version text not NULL, + layer text not NULL, + layer_description text not NULL, + timeslot_id bigint not NULL unique, + CONSTRAINT blueprint_instance_id_pk PRIMARY KEY (blueprint_instance_id), + CONSTRAINT blueprint_id_fk FOREIGN KEY (blueprint_id) + REFERENCES akraino.blueprint (blueprint_id) MATCH SIMPLE + ON UPDATE NO ACTION ON DELETE NO ACTION, + CONSTRAINT timeslot_id_fk FOREIGN KEY (timeslot_id) + REFERENCES akraino.timeslot (timeslot_id) MATCH SIMPLE + ON UPDATE NO ACTION ON DELETE NO ACTION +) +WITH ( + OIDS = FALSE +) +; +ALTER TABLE akraino.blueprint_instance + OWNER TO postgres; + +CREATE TABLE akraino.submission +( + submission_id bigint not NULL, + status text not NULL, + jenkins_queue_job_item_url text, + nexus_result_url text, + blueprint_instance_id bigint not NULL, + CONSTRAINT submission_id_pk PRIMARY KEY (submission_id), + CONSTRAINT blueprint_instance_id_fk FOREIGN KEY (blueprint_instance_id) + REFERENCES akraino.blueprint_instance (blueprint_instance_id) MATCH SIMPLE + ON UPDATE NO ACTION ON DELETE NO ACTION +) +WITH ( + OIDS = FALSE +) +; +ALTER TABLE akraino.submission + OWNER TO postgres; + +CREATE SEQUENCE akraino.seq_timeslot + START WITH 1 INCREMENT BY 1; + +CREATE SEQUENCE akraino.seq_blueprint + START WITH 1 INCREMENT BY 1; + +CREATE SEQUENCE akraino.seq_blueprint_instance + START WITH 1 INCREMENT BY 1; + +CREATE SEQUENCE akraino.seq_submission + START WITH 1 INCREMENT BY 1; + +insert into akraino.timeslot values(1, now(), 10, 0); /* stands for AT&T lab */ +insert into akraino.timeslot values(2, now(), 1000, 0); /* stands for AT&T lab */ +insert into akraino.timeslot values(3, now(), 10000, 0); /* stands for AT&T lab */ +insert into akraino.timeslot values(4, now(), 100000, 0); /* stands for AT&T lab */ +insert into akraino.timeslot values(5, now(), 100000, 0); /* stands for AT&T lab */ + +insert into akraino.blueprint (blueprint_id, blueprint_name) values(1, 'dummy'); +insert into akraino.blueprint (blueprint_id, blueprint_name) values(2, 'Unicycle'); +insert into akraino.blueprint (blueprint_id, blueprint_name) values(3, 'REC'); + +insert into akraino.blueprint_instance (blueprint_instance_id, blueprint_id, version, layer, layer_description, timeslot_id) values(1, 1, '0.0.2-SNAPSHOT', 0, 'Dell Hardware', 1); /* 0 Stands for hardware layer */ +insert into akraino.blueprint_instance (blueprint_instance_id, blueprint_id, version, layer, layer_description, timeslot_id) values(2, 2, '0.0.1-SNAPSHOT', 0, 'Dell Hardware', 2); /* 0 Stands for hardware layer */ +insert into akraino.blueprint_instance (blueprint_instance_id, blueprint_id, version, layer, layer_description, timeslot_id) values(3, 2, '0.0.7-SNAPSHOT', 1, 'CentOS Linux 7 (Core)', 3); /* 1 Stands for OS layer */ +insert into akraino.blueprint_instance (blueprint_instance_id, blueprint_id, version, layer, layer_description, timeslot_id) values(4, 3, '0.0.4-SNAPSHOT', 2, 'K8s with High Availability Ingress controller', 4); /* 2 Stands for k8s layer */ +insert into akraino.blueprint_instance (blueprint_instance_id, blueprint_id, version, layer, layer_description, timeslot_id) values(5, 3, '0.0.8-SNAPSHOT', 2, 'K8s with High Availability Ingress controller', 5); /* 2 Stands for k8s layer */ + +commit; diff --git a/docker/postgresql/deploy.sh b/docker/postgresql/deploy.sh new file mode 100755 index 0000000..60af84e --- /dev/null +++ b/docker/postgresql/deploy.sh @@ -0,0 +1,54 @@ +#!/bin/bash +# +# Copyright (c) 2019 AT&T Intellectual Property. All other rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +export DROOT=/var/lib +CONTAINER_NAME="validation_postgresql" +POSTGRES_HOST_PORT=6432 +REGISTRY=akraino +NAME=validation +TAG_PRE=`echo "${PWD##*/}"` +TAG_VER=latest +POSTGRES_PASSWORD="" +HOST_ARCH=amd64 + +# get the architecture of the host +if [ "`uname -m`" = "aarch64" ]; then + HOST_ARCH=arm64 +fi + +for ARGUMENT in "$@" +do + KEY=$(echo $ARGUMENT | cut -f1 -d=) + VALUE=$(echo $ARGUMENT | cut -f2 -d=) + case "$KEY" in + REGISTRY) REGISTRY=${VALUE} ;; + NAME) NAME=${VALUE} ;; + TAG_VER) TAG_VER=${VALUE} ;; + POSTGRES_PASSWORD) POSTGRES_PASSWORD=${VALUE} ;; + *) + esac +done + +if [ -z "$POSTGRES_PASSWORD" ] + then + echo "ERROR: You must specify at least the postgreSQL database password" + exit 1 +fi + +IMAGE="$REGISTRY"/"$NAME":"$TAG_PRE"-"$HOST_ARCH"-"$TAG_VER" +docker run --detach --name $CONTAINER_NAME --restart=always --publish $POSTGRES_HOST_PORT:5432 --volume $DROOT/postgres:/var/lib/postgresql/data --env POSTGRES_USER=admin --env POSTGRES_PASSWORD="$POSTGRES_PASSWORD" $IMAGE +sleep 10 +docker exec $CONTAINER_NAME /bin/bash -c "psql -h localhost -p 5432 -U admin -f /akraino-blueprint_validation_db.sql" diff --git a/docker/ui/Dockerfile b/docker/ui/Dockerfile new file mode 100644 index 0000000..ee710a1 --- /dev/null +++ b/docker/ui/Dockerfile @@ -0,0 +1,18 @@ +# +# Copyright (c) 2019 AT&T Intellectual Property. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +FROM tomcat:8.5.37 +COPY ./AECBlueprintValidationUI.war /usr/local/tomcat/webapps \ No newline at end of file diff --git a/docker/ui/Makefile b/docker/ui/Makefile new file mode 100644 index 0000000..5e2d074 --- /dev/null +++ b/docker/ui/Makefile @@ -0,0 +1,27 @@ +############################################################################## +# Copyright (c) 2019 AT&T Intellectual Property. All rights reserved. # +# # +# Licensed under the Apache License, Version 2.0 (the "License"); # +# you maynot use this file except in compliance with the License. # +# # +# You may obtain a copy of the License at # +# http://www.apache.org/licenses/LICENSE-2.0 # +# # +# Unless required by applicable law or agreed to in writing, software # +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT # +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # +# See the License for the specific language governing permissions and # +# limitations under the License. # +############################################################################## + +.PHONY: prepare +prepare: + ln -f ../../ui/target/AECBlueprintValidationUI.war AECBlueprintValidationUI.war + +.PHONY: all +all: prepare .push_image .push_manifest + +.PHONY: build +build: prepare .build + +include ../build.mk \ No newline at end of file diff --git a/docker/ui/deploy.sh b/docker/ui/deploy.sh new file mode 100755 index 0000000..fef0bed --- /dev/null +++ b/docker/ui/deploy.sh @@ -0,0 +1,96 @@ +#!/bin/bash +# +# Copyright (c) 2019 AT&T Intellectual Property. All other rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +CONTAINER_NAME="validation-ui" +REGISTRY=akraino +NAME=validation +TAG_PRE=`echo "${PWD##*/}"` +TAG_VER=latest +HOST_ARCH=amd64 +postgres_db_user_pwd="" +jenkins_url="" +jenkins_user_name="" +jenkins_user_pwd="" +jenkins_job_name="" +nexus_results_url="" +proxy_ip="" +proxy_port="" + +# get the architecture of the host +if [ "`uname -m`" = "aarch64" ] + then + HOST_ARCH=arm64 +fi + +for ARGUMENT in "$@" +do + KEY=$(echo $ARGUMENT | cut -f1 -d=) + VALUE=$(echo $ARGUMENT | cut -f2 -d=) + case "$KEY" in + REGISTRY) REGISTRY=${VALUE} ;; + NAME) NAME=${VALUE} ;; + TAG_VER) TAG_VER=${VALUE} ;; + postgres_db_user_pwd) postgres_db_user_pwd=${VALUE} ;; + jenkins_url) jenkins_url=${VALUE} ;; + jenkins_user_name) jenkins_user_name=${VALUE} ;; + jenkins_user_pwd) jenkins_user_pwd=${VALUE} ;; + jenkins_job_name) jenkins_job_name=${VALUE} ;; + nexus_results_url) nexus_results_url=${VALUE} ;; + proxy_ip) proxy_ip=${VALUE} ;; + proxy_port) proxy_port=${VALUE} ;; + *) + esac +done + +if [ -z "$postgres_db_user_pwd" ] + then + echo "ERROR: You must specify the postgresql root user password" + exit 1 +fi + +if [ -z "$jenkins_url" ] + then + echo "ERROR: You must specify the Jenkins Url" + exit 1 +fi + +if [ -z "$jenkins_user_name" ] + then + echo "ERROR: You must specify the Jenkins username" + exit 1 +fi + +if [ -z "$jenkins_user_pwd" ] + then + echo "ERROR: You must specify the Jenkins user password" + exit 1 +fi + +if [ -z "$jenkins_job_name" ] + then + echo "ERROR: You must specify the Jenkins job name" + exit 1 +fi + +if [ -z "$nexus_results_url" ] + then + echo "ERROR: You must specify the Nexus Url" + exit 1 +fi + +IMAGE="$REGISTRY"/"$NAME":"$TAG_PRE"-"$HOST_ARCH"-"$TAG_VER" +docker run --name $CONTAINER_NAME --network="host" -it --rm -e postgres_db_user_pwd="$postgres_db_user_pwd" -e jenkins_url="$jenkins_url" -e jenkins_user_name="$jenkins_user_name" -e jenkins_user_pwd="$jenkins_user_pwd" -e jenkins_job_name="$jenkins_job_name" -e nexus_results_url="$nexus_results_url" -e proxy_ip="$proxy_ip" -e proxy_port="$proxy_port" $IMAGE +sleep 10 diff --git a/tox.ini b/tox.ini index 64c1486..a1cdceb 100644 --- a/tox.ini +++ b/tox.ini @@ -14,6 +14,11 @@ commands = [testenv:coala] basepython = python3 +whitelist_externals = + wget + unzip + bash + passenv = http_proxy HTTP_PROXY https_proxy HTTPS_PROXY no_proxy NO_PROXY install_command = python -m pip install --no-cache-dir {opts} {packages} deps = @@ -24,5 +29,7 @@ deps = nodeenv commands = nodeenv -p - npm install --global write-good - coala --non-interactive + npm install --global write-good eslint complexity-report@2.0.0-alpha + wget --timeout=120 -q https://github.com/pmd/pmd/releases/download/pmd_releases/6.15.0/pmd-bin-6.15.0.zip + unzip -q pmd-bin-6.15.0.zip + bash -c "export PATH=$PATH:$PWD/pmd-bin-6.15.0/bin/ && coala --non-interactive" \ No newline at end of file diff --git a/ui/CHANGELOG.md b/ui/CHANGELOG.md new file mode 100644 index 0000000..fd87d9b --- /dev/null +++ b/ui/CHANGELOG.md @@ -0,0 +1,62 @@ +# Changelog +All notable changes to this project will be documented in this file. + +## [Unreleased] + +## [0.0.1-SNAPSHOT] - 4 June 2019 +### Added +- A user can commit and be informed about submissions of blueprint validation requests. +- Appropriate dockerfiles have been added for the UI and the required postgreSQL db. +- .gitignore file has been updated +- Integration with Jenkins completed +- The URL of the result is retrieved and displayed +- Multi-threading is now supported +- Notification callback from Jenkins implemented +- Results are retrieved from Nexus +- Results are displayed +- UI and postgreSQL docker projects support the makefile automation build and push process +- README file is included +- CHANGELOG is included +- Coala static code analysis performed for Java and JS files + +### Changed + +### Removed + +## [0.0.1-SNAPSHOT] - 5 June 2019 +### Added + +### Changed +- PostgreSQL database model has been refactored in order to support 4 tables, namely timeslot, blueprint, blueprint_instance, submission +- Trailing spaces removed from comments in javascript files + +### Removed + +## [0.0.1-SNAPSHOT] - 6 June 2019 +### Added +- Community lab is now supported + +### Changed +- README file is updated. +- Coala static analysis issues fixed for Javascript files +- README.md has been renamed to README.rst + +### Removed + +## [0.0.1-SNAPSHOT] - 7 June 2019 +### Added +- Arm lab is now supported + +### Changed +- README file is updated. + +### Removed + +## [0.0.1-SNAPSHOT] - 10 June 2019 +### Added + +### Changed +- Trailing spaces removed from all files. +- README file is updated. + +### Removed \ No newline at end of file diff --git a/ui/README.rst b/ui/README.rst new file mode 100644 index 0000000..73ec832 --- /dev/null +++ b/ui/README.rst @@ -0,0 +1,177 @@ + +Akraino Blueprint Validation UI +======== + +This project contains the source code of the Akraino Blueprint Validation UI. + +This UI consists of the front-end and back-end parts. +The front-end part is based on HTML, CSS, and AngularJS technologies. +The back-end part is based on Spring MVC and Apache Tomcat technologies. + +Based on these instructions, a user can provide the prerequisites, compile the source code and deploy the UI. + +Download the project +-------------------- + +.. code-block:: console + + git clone "https://gerrit.akraino.org/r/validation" + +Prerequisites +--------------- + +- Database + +A PostgreSQL database instance is needed with the appropriate relations in order for the back-end system to store and retrieve data. +Configure the postgreSQL root password in the variable POSTGRES_PASSWORD and execute the following commands in order to build and deploy this database container: + +.. code-block:: console + + cd validation/docker/postgresql + make build + ./deploy.sh POSTGRES_PASSWORD=password + +Below, some data that is initialized in the aforementioned database is illustrated (note that this data is used mainly for testing purposes): + +.. code-block:: console + + Timeslots: + id:1 , start date and time: now() (i.e. the time of the postgreSQL container deployment), duration: 10 (sec), lab: 0 (i.e. AT&T) + id:2 , start date and time: now() (i.e. the time of the postgreSQL container deployment), duration: 1000 (sec), lab: 0 (i.e. AT&T) + + Blueprints: + id: 1 , name : 'dummy' + id: 2 , name : 'Unicycle' + + Blueprint Instances: + id: 1, blueprint_id: 1 (i.e. dummy), version: "0.0.2-SNAPSHOT", layer: 0 (i.e. Hardware), layer_description: "Dell Hardware", timeslot id: 1 + id: 2, blueprint_id: 2 (i.e. Unicycle), version: "0.0.1-SNAPSHOT", layer: 0 (i.e. Hardware), layer_description: "Dell Hardware", timeslot id: 2 + +For more information about this data, please refer to the file: + + validation/docker/postgresql/akraino-blueprint_validation_db.sql + +Based on this data, the UI enables the user to select an appropriate blueprint instance for validation. + +Currently, this data cannot be retrieved dynamically by the UI (see limitations subsection). + +For this reason, in cases of new blueprint data, a user should define new entries in this database. + +For example, if a user wants to define a new timeslot with the following data: + + start date and time:now, duration: 123 in secs, lab: Community + +the following file should be created: + +name: dbscript +content: + insert into akraino.timeslot values(5, now(), 123, 2); + +Then, the following command should be executed: + +.. code-block:: console + + psql -h -p 6432 -U admin -f ./dbscript + +Furthermore, if a user wants to define a new blueprint, namely "newBlueprint" and a new instance of this blueprint with the following data: + + version: "0.0.1-SNAPSHOT", layer: 2 (i.e. K8s), layer_description: "K8s with High Availability Ingress controller", timeslot id: 5 (i.e. the new timeslot) + +the following file should be created: + +name: dbscript +content: + insert into akraino.blueprint (blueprint_id, blueprint_name) values(4, 'newBlueprint'); + insert into akraino.blueprint_instance (blueprint_instance_id, blueprint_id, version, layer, layer_description, timeslot_id) values(6, 4, '0.0.1-SNAPSHOT', 2, 'K8s with High Availability Ingress controller', 5); + +Then, the following command should be executed: + +.. code-block:: console + + psql -h -p 6432 -U admin -f ./dbscript + +The UI will automatically retrieve this new data and display it to the user. + +- Jenkins Configuration + +The Blueprint validation UI will trigger job executions in a Jenkins instance. + +This instance must have the following option enabled: "Manage Jenkins -> Configure Global Security -> Prevent Cross Site Request Forgery exploits". + +Also, currently corresponding Jenkins job should accept the following as input parameters: "SUBMISSION_ID", "BLUEPRINT", "LAYER" and "UI_IP". +The "SUBMISSION_ID" and "UI_IP" parameters (i.e. IP address of the UI host machine-this is needed by the Jenkins instance in order to send back Job completion notification) are created and provided by the backend part of the UI. +The "BLUEPRINT" and "LAYER" parameters are configured by the UI user. + +Moreover, as the Jenkins notification plugin (https://wiki.jenkins.io/display/JENKINS/Notification+Plugin) seems to ignore proxy settings, the corresponding Jenkins job must be configured to execute the following command at the end (Post-build Actions) + +.. code-block:: console + + curl -v -H "Content-Type: application/json" -X POST --insecure --silent http://$UI_IP:8080/AECBlueprintValidationUI/api/jenkinsJobNotification/ --data '{"submissionId": "'"$SUBMISSION_ID"'" , "name":"'"$JOB_NAME"'", "buildNumber":"'"$BUILD_NUMBER"'"}' + +Finally, the Jenkins instance must be accessible from the UI host without using system proxy. + +- Nexus server + +All the blueprint validation results are stored in Nexus server. + +These results must be available in the following url: + + https://nexus.akraino.org/content/sites/logs/"lab"-blu-val/job/validation/"Jenkins job number"/results/"name_of_the_test_suite". + +where "lab" is the name of the lab (for example 'att'), "Jenkins job number" is the number of the Jenkins job that produced this result, and "name_of_the_test_suite" is the name of the test suite. +If multiple test suites must run, multiple directories should be created. + +Moreover, the results should be stored in the 'output.xml' file using the following format: + +TBD + +Finally, the Nexus server must be accessible from the UI (with or without using system proxy). + + +Compiling +--------- + +.. code-block:: console + + cd validation/ui + mvn clean install + +Deploying +--------- + +In the context of deploying, the following data is needed: + +- The postgres root user password +- The Jenkins url +- The Jenkins username and password +- The name of Jenkins Job +- The Url of the Nexus results +- The host system's proxy ip and port + +These variables must be configured as content of the deploy script input parameters. Execute the following commands in order to build and deploy the UI container: + +.. code-block:: console + + cd validation/docker/ui + make build + ./deploy.sh postgres_db_user_pwd=password jenkins_url=http://192.168.2.2:8080 jenkins_user_name=name jenkins_user_pwd=jenkins_pwd jenkins_job_name=job1 nexus_results_url=https://nexus.akraino.org/content/sites/logs proxy_ip=172.28.40.9 proxy_port=3128 + +If no proxy exists, just do not define proxy ip and port variables. + +The UI should be available in the following url: + + http://localhost:8080/AECBlueprintValidationUI + +Limitations +----------- + +- The UI has been tested using Chrome and Firefox browsers. +- The UI is not connected to any LDAP server. Currently, any user can login. +- The UI and postgreSQL containers must be deployed on the same server. +- The back-end part of the UI does not take into account the configured timeslot. It immediately triggers the corresponding Jenkins Job. +- Results data manipulation (filtering, graphical representation, indexing in time order, etc) is not supported. +- Only the following labs are supported: AT&T, Ericsson, Community and Arm. +- Only the following tabs are functional: 'Committed Submissions', 'Blueprint Validation Results -> Get by submission id'. +- The UI configures only the "BLUEPRINT" and "LAYER" input parameters of the Jenkins job. +- The available blueprints and timeslots must be manually configured in the PostgreSQL database. +- The Jenkins instance must be accessible from the UI host without using system proxy. \ No newline at end of file diff --git a/ui/pom.xml b/ui/pom.xml new file mode 100755 index 0000000..85890da --- /dev/null +++ b/ui/pom.xml @@ -0,0 +1,236 @@ + + + + 4.0.0 + org.akraino.validation + ui + war + 0.0.1-SNAPSHOT + AECBlueprintValidationUI Maven Webapp + http://maven.apache.org + + 1.8 + 4.3.0.RELEASE + 3.2.3.RELEASE + 2.7.5 + UTF-8 + 1.19.4 + 27.1-jre + + + + + central + Central Repository + http://repo.maven.apache.org/maven2 + default + + false + + + + + + + central + Maven Plugin Repository + http://repo1.maven.org/maven2 + default + + false + + + never + + + + + + + junit + junit + 4.12 + test + + + commons-codec + commons-codec + 1.11 + + + org.springframework + spring-webmvc + ${org.springframework-version} + + + org.springframework + spring-context + ${org.springframework-version} + + + org.springframework + spring-orm + ${org.springframework-version} + + + org.springframework + spring-tx + ${org.springframework-version} + + + commons-fileupload + commons-fileupload + 1.3.2 + + + org.hibernate + hibernate-core + 5.2.6.Final + + + org.javassist + javassist + 3.18.2-GA + + + org.hibernate + hibernate-c3p0 + 5.2.6.Final + + + commons-dbcp + commons-dbcp + 1.4 + + + com.mchange + c3p0 + 0.9.5.2 + + + org.hibernate + hibernate-validator + 5.4.1.Final + + + log4j + log4j + 1.2.17 + + + org.springframework + spring-test + ${org.springframework-version} + test + + + javax.servlet + javax.servlet-api + 3.0.1 + provided + + + javax.servlet + jstl + 1.2 + + + com.fasterxml.jackson.core + jackson-databind + ${jackson.library} + + + com.fasterxml.jackson.dataformat + jackson-dataformat-xml + ${jackson.library} + + + com.fasterxml.jackson.dataformat + jackson-dataformat-yaml + ${jackson.library} + + + org.apache.commons + commons-lang3 + 3.4 + + + org.postgresql + postgresql + 42.2.2 + + + com.sun.jersey + jersey-json + ${jersey-version} + + + com.sun.jersey + jersey-client + ${jersey-version} + + + com.google.guava + guava + ${google.guava-version} + + + org.json + json + 20180813 + + + org.jsoup + jsoup + 1.12.1 + + + commons-httpclient + commons-httpclient + 3.1 + + + + + + AECBlueprintValidationUI + + + + org.apache.maven.plugins + maven-compiler-plugin + 2.3.2 + + ${java-version} + ${java-version} + + + + org.apache.maven.plugins + maven-war-plugin + 2.4 + + src/main/webapp + AECBlueprintValidationUI + false + + + + + + diff --git a/ui/src/main/java/org/akraino/validation/ui/client/jenkins/JenkinsExecutorClient.java b/ui/src/main/java/org/akraino/validation/ui/client/jenkins/JenkinsExecutorClient.java new file mode 100644 index 0000000..313ce89 --- /dev/null +++ b/ui/src/main/java/org/akraino/validation/ui/client/jenkins/JenkinsExecutorClient.java @@ -0,0 +1,228 @@ +/* + * Copyright (c) 2019 AT&T Intellectual Property. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.akraino.validation.ui.client.jenkins; + +import java.net.MalformedURLException; +import java.net.URL; +import java.security.KeyManagementException; +import java.security.NoSuchAlgorithmException; +import java.security.cert.X509Certificate; +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; +import java.util.Map; + +import javax.annotation.Nonnull; +import javax.net.ssl.HostnameVerifier; +import javax.net.ssl.HttpsURLConnection; +import javax.net.ssl.SSLContext; +import javax.net.ssl.SSLSession; +import javax.net.ssl.TrustManager; +import javax.net.ssl.X509TrustManager; +import javax.ws.rs.core.MultivaluedMap; + +import org.akraino.validation.ui.client.jenkins.resources.CrumbResponse; +import org.akraino.validation.ui.client.jenkins.resources.Parameter; +import org.akraino.validation.ui.client.jenkins.resources.Parameters; +import org.akraino.validation.ui.client.jenkins.resources.QueueJobItem; +import org.apache.commons.httpclient.HttpException; +import org.apache.log4j.Logger; + +import com.sun.jersey.api.client.Client; +import com.sun.jersey.api.client.ClientHandlerException; +import com.sun.jersey.api.client.ClientResponse; +import com.sun.jersey.api.client.UniformInterfaceException; +import com.sun.jersey.api.client.WebResource; +import com.sun.jersey.api.client.config.ClientConfig; +import com.sun.jersey.api.client.config.DefaultClientConfig; +import com.sun.jersey.api.client.filter.HTTPBasicAuthFilter; +import com.sun.jersey.api.json.JSONConfiguration; +import com.sun.jersey.client.urlconnection.HTTPSProperties; + +public final class JenkinsExecutorClient { + + private static final Logger LOGGER = Logger.getLogger(JenkinsExecutorClient.class); + + private static final List JENKINS_CLIENTS = new ArrayList<>(); + private static final Object LOCK = new Object(); + private final Client client; + + private final String user; + private final String password; + private final String baseurl; + + private final HostnameVerifier hostnameVerifier; + private final TrustManager[] trustAll; + + private JenkinsExecutorClient(String newUser, String newPassword, String newBaseurl) { + this.user = newUser; + this.password = newPassword; + this.baseurl = newBaseurl; + ClientConfig clientConfig = new DefaultClientConfig(); + clientConfig.getFeatures().put(JSONConfiguration.FEATURE_POJO_MAPPING, Boolean.TRUE); + this.client = Client.create(clientConfig); + this.client.addFilter(new HTTPBasicAuthFilter(user, password)); + // Create all-trusting host name verifier + hostnameVerifier = new HostnameVerifier() { + @Override + public boolean verify(String hostname, SSLSession session) { + return true; + } + }; + // Create a trust manager that does not validate certificate chains + trustAll = new TrustManager[] {new X509TrustManager() { + @Override + public X509Certificate[] getAcceptedIssuers() { + return null; // Not relevant. + } + + @Override + public void checkClientTrusted(X509Certificate[] certs, String authType) { + // Do nothing. Just allow them all. + } + + @Override + public void checkServerTrusted(X509Certificate[] certs, String authType) { + // Do nothing. Just allow them all. + } + }}; + } + + public static synchronized JenkinsExecutorClient getInstance(@Nonnull String newUser, @Nonnull String newPassword, + @Nonnull String newBaseurl) throws MalformedURLException { + new URL(newBaseurl); + for (JenkinsExecutorClient client : JENKINS_CLIENTS) { + if (client.getBaseUrl().equals(newBaseurl) && client.getUser().equals(newUser) + && client.getPassword().equals(newPassword)) { + return client; + } + } + JenkinsExecutorClient client = new JenkinsExecutorClient(newUser, newPassword, newBaseurl); + JENKINS_CLIENTS.add(client); + return client; + } + + public String getUser() { + return this.user; + } + + public String getPassword() { + return this.password; + } + + public String getBaseUrl() { + return this.baseurl; + } + + public QueueJobItem getQueueJobItem(URL queueJobItemUrl) throws HttpException, ClientHandlerException, + UniformInterfaceException, KeyManagementException, NoSuchAlgorithmException { + synchronized (LOCK) { + LOGGER.info("Trying to get a Jenkins resource"); + String crumb = this.getCrumb(); + LOGGER.debug("Jenkins crumb is: " + crumb); + WebResource webResource = this.client.resource(queueJobItemUrl + "/api/json"); + LOGGER.debug("Request URI of get: " + webResource.getURI().toString()); + WebResource.Builder builder = webResource.getRequestBuilder(); + builder.header("Jenkins-Crumb", crumb); + ClientResponse response = + builder.accept("application/json").type("application/json").get(ClientResponse.class); + if (response.getStatus() != 200) { + throw new HttpException("Get on Jenkins failed. HTTP error code : " + response.getStatus() + + " and message: " + response.getEntity(String.class)); + } + LOGGER.info("Get of Jenkins resource succeeded"); + return response.getEntity(QueueJobItem.class); + } + } + + /** + * + * @param jobName + * @param parameters + * @return The URL of the corresponding Jenkins queue job item + * @throws UniformInterfaceException + * @throws ClientHandlerException + * @throws HttpException + * @throws MalformedURLException + * @throws NoSuchAlgorithmException + * @throws KeyManagementException + */ + public URL postJobWithQueryParams(@Nonnull String jobName, @Nonnull Parameters parameters) + throws HttpException, ClientHandlerException, UniformInterfaceException, MalformedURLException, + KeyManagementException, NoSuchAlgorithmException { + synchronized (LOCK) { + LOGGER.info("Trying to trigger a job to Jenkins"); + String crumb = this.getCrumb(); + LOGGER.debug("Jenkins crumb is: " + crumb); + String queryParams = "?"; + for (Parameter parameter : parameters.getParameter()) { + queryParams = queryParams + parameter.getName() + "=" + parameter.getValue() + "&"; + } + queryParams = queryParams.substring(0, queryParams.length() - 1); + WebResource webResource = + this.client.resource(this.getBaseUrl() + "/job/" + jobName + "/buildWithParameters" + queryParams); + LOGGER.debug("Request URI of post: " + webResource.getURI().toString()); + WebResource.Builder builder = webResource.getRequestBuilder(); + builder.header("Jenkins-Crumb", crumb); + ClientResponse response = builder.type("application/json").post(ClientResponse.class, String.class); + if (response.getStatus() != 200 && response.getStatus() != 201) { + throw new HttpException("Post of Jenkins job failed. HTTP error code : " + response.getStatus() + + " and message: " + response.getEntity(String.class)); + } + LOGGER.info("Jenkins job has been successfully triggered"); + URL buildQueueUrl = null; + MultivaluedMap responseValues = response.getHeaders(); + Iterator iter = responseValues.keySet().iterator(); + while (iter.hasNext()) { + String key = iter.next(); + if (key.equals("Location")) { + buildQueueUrl = new URL(responseValues.getFirst(key)); + } + } + return buildQueueUrl; + } + } + + private String getCrumb() throws HttpException, ClientHandlerException, UniformInterfaceException, + KeyManagementException, NoSuchAlgorithmException { + LOGGER.info("Get crumb attempt"); + setProperties(); + String crumbUri = baseurl + "/crumbIssuer/api/json"; + WebResource webResource = this.client.resource(crumbUri); + ClientResponse response = + webResource.accept("application/json").type("application/json").get(ClientResponse.class); + if (response.getStatus() == 201 || response.getStatus() == 200) { + CrumbResponse crumbResponse = response.getEntity(CrumbResponse.class); + LOGGER.info("Successful crumb retrieval."); + return crumbResponse.getCrumb(); + } + throw new HttpException("Get crumb attempt towards Jenkins failed. HTTP error code: " + response.getStatus() + + " and message: " + response.getEntity(String.class)); + } + + private void setProperties() throws NoSuchAlgorithmException, KeyManagementException { + SSLContext sslContext = SSLContext.getInstance("SSL"); + sslContext.init(null, this.trustAll, new java.security.SecureRandom()); + HttpsURLConnection.setDefaultSSLSocketFactory(sslContext.getSocketFactory()); + // Install the all-trusting host verifier + HttpsURLConnection.setDefaultHostnameVerifier(this.hostnameVerifier); + DefaultClientConfig config = new DefaultClientConfig(); + Map properties = config.getProperties(); + HTTPSProperties httpsProperties = new HTTPSProperties((str, sslSession) -> true, sslContext); + properties.put(HTTPSProperties.PROPERTY_HTTPS_PROPERTIES, httpsProperties); + } + +} diff --git a/ui/src/main/java/org/akraino/validation/ui/client/jenkins/resources/CrumbResponse.java b/ui/src/main/java/org/akraino/validation/ui/client/jenkins/resources/CrumbResponse.java new file mode 100644 index 0000000..5cf4518 --- /dev/null +++ b/ui/src/main/java/org/akraino/validation/ui/client/jenkins/resources/CrumbResponse.java @@ -0,0 +1,63 @@ +/* + * Copyright (c) 2019 AT&T Intellectual Property. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.akraino.validation.ui.client.jenkins.resources; + +import org.codehaus.jackson.annotate.JsonIgnoreProperties; +import org.codehaus.jackson.annotate.JsonProperty; +import org.codehaus.jackson.map.annotate.JsonSerialize; + +@JsonIgnoreProperties(ignoreUnknown = true) +@JsonSerialize(include = JsonSerialize.Inclusion.NON_NULL) +public class CrumbResponse implements IResource { + + @JsonProperty("_class") + private String classCrumb; + + @JsonProperty("crumb") + private String crumb; + + @JsonProperty("crumbRequestField") + private String crumbRequestField; + + public CrumbResponse() { + + } + + public String getClassCrumb() { + return this.classCrumb; + } + + public void setClassCrumb(String classCrumb) { + this.classCrumb = classCrumb; + } + + public String getCrumb() { + return this.crumb; + } + + public void setCrumb(String crumb) { + this.crumb = crumb; + } + + public String getCrumbRequestField() { + return this.crumbRequestField; + } + + public void setCrumbRequestField(String crumbRequestField) { + this.crumbRequestField = crumbRequestField; + } + +} diff --git a/ui/src/main/java/org/akraino/validation/ui/client/jenkins/resources/IResource.java b/ui/src/main/java/org/akraino/validation/ui/client/jenkins/resources/IResource.java new file mode 100644 index 0000000..ac00cbe --- /dev/null +++ b/ui/src/main/java/org/akraino/validation/ui/client/jenkins/resources/IResource.java @@ -0,0 +1,20 @@ +/* + * Copyright (c) 2019 AT&T Intellectual Property. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.akraino.validation.ui.client.jenkins.resources; + +public interface IResource { + +} diff --git a/ui/src/main/java/org/akraino/validation/ui/client/jenkins/resources/Parameter.java b/ui/src/main/java/org/akraino/validation/ui/client/jenkins/resources/Parameter.java new file mode 100644 index 0000000..3557421 --- /dev/null +++ b/ui/src/main/java/org/akraino/validation/ui/client/jenkins/resources/Parameter.java @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2019 AT&T Intellectual Property. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.akraino.validation.ui.client.jenkins.resources; + +import org.codehaus.jackson.annotate.JsonIgnoreProperties; +import org.codehaus.jackson.annotate.JsonProperty; +import org.codehaus.jackson.map.annotate.JsonSerialize; + +@JsonIgnoreProperties(ignoreUnknown = true) +@JsonSerialize(include = JsonSerialize.Inclusion.NON_NULL) +public class Parameter { + @JsonProperty("name") + private String name; + + @JsonProperty("value") + private String value; + + public String getName() { + return this.name; + } + + public void setName(String name) { + this.name = name; + } + + public String getValue() { + return this.value; + } + + public void setValue(String value) { + this.value = value; + } +} + + diff --git a/ui/src/main/java/org/akraino/validation/ui/client/jenkins/resources/Parameters.java b/ui/src/main/java/org/akraino/validation/ui/client/jenkins/resources/Parameters.java new file mode 100644 index 0000000..8fad211 --- /dev/null +++ b/ui/src/main/java/org/akraino/validation/ui/client/jenkins/resources/Parameters.java @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2019 AT&T Intellectual Property. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.akraino.validation.ui.client.jenkins.resources; + +import java.util.List; + +import org.codehaus.jackson.annotate.JsonIgnoreProperties; +import org.codehaus.jackson.annotate.JsonProperty; +import org.codehaus.jackson.map.annotate.JsonSerialize; + +@JsonIgnoreProperties(ignoreUnknown = true) +@JsonSerialize(include = JsonSerialize.Inclusion.NON_NULL) +public class Parameters implements IResource { + + @JsonProperty("parameter") + private List parameter; + + public List getParameter() { + return this.parameter; + } + + public void setParameter(List parameter) { + this.parameter = parameter; + } + +} diff --git a/ui/src/main/java/org/akraino/validation/ui/client/jenkins/resources/QueueJobItem.java b/ui/src/main/java/org/akraino/validation/ui/client/jenkins/resources/QueueJobItem.java new file mode 100644 index 0000000..9da3891 --- /dev/null +++ b/ui/src/main/java/org/akraino/validation/ui/client/jenkins/resources/QueueJobItem.java @@ -0,0 +1,89 @@ +/* + * Copyright (c) 2019 AT&T Intellectual Property. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.akraino.validation.ui.client.jenkins.resources; + +import java.net.URL; + +import org.codehaus.jackson.annotate.JsonIgnoreProperties; +import org.codehaus.jackson.annotate.JsonProperty; +import org.codehaus.jackson.map.annotate.JsonSerialize; + +@JsonIgnoreProperties(ignoreUnknown = true) +@JsonSerialize(include = JsonSerialize.Inclusion.NON_NULL) +public class QueueJobItem implements IResource { + + @JsonProperty("_class") + private String classQueue; + + @JsonProperty("executable") + private Executable executable; + + public QueueJobItem() { + + } + + public String getClassQueue() { + return this.classQueue; + } + + public void setClassQueue(String classQueue) { + this.classQueue = classQueue; + } + + public Executable getExecutable() { + return this.executable; + } + + public void setExecutable(Executable executable) { + this.executable = executable; + } + + public class Executable { + @JsonProperty("_class") + private String classQueue; + + @JsonProperty("number") + private Integer number; + + @JsonProperty("url") + private URL url; + + public String getClassQueue() { + return this.classQueue; + } + + public void setClassQueue(String classQueue) { + this.classQueue = classQueue; + } + + public Integer getNumber() { + return this.number; + } + + public void setNumber(Integer number) { + this.number = number; + } + + public URL getUrl() { + return this.url; + } + + public void setUrl(URL url) { + this.url = url; + } + } + +} diff --git a/ui/src/main/java/org/akraino/validation/ui/client/nexus/NexusExecutorClient.java b/ui/src/main/java/org/akraino/validation/ui/client/nexus/NexusExecutorClient.java new file mode 100644 index 0000000..988685b --- /dev/null +++ b/ui/src/main/java/org/akraino/validation/ui/client/nexus/NexusExecutorClient.java @@ -0,0 +1,168 @@ +/* + * Copyright (c) 2019 AT&T Intellectual Property. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.akraino.validation.ui.client.nexus; + +import java.io.IOException; +import java.net.HttpURLConnection; +import java.net.InetSocketAddress; +import java.net.Proxy; +import java.net.URL; +import java.security.KeyManagementException; +import java.security.NoSuchAlgorithmException; +import java.security.cert.X509Certificate; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + +import javax.net.ssl.HostnameVerifier; +import javax.net.ssl.HttpsURLConnection; +import javax.net.ssl.SSLContext; +import javax.net.ssl.SSLSession; +import javax.net.ssl.TrustManager; +import javax.net.ssl.X509TrustManager; + +import org.akraino.validation.ui.client.nexus.resources.RobotTestResult; +import org.apache.commons.httpclient.HttpException; +import org.apache.log4j.Logger; +import org.json.JSONObject; +import org.json.XML; +import org.jsoup.Jsoup; +import org.jsoup.nodes.Document; +import org.jsoup.nodes.Element; + +import com.fasterxml.jackson.core.JsonParseException; +import com.fasterxml.jackson.databind.DeserializationFeature; +import com.fasterxml.jackson.databind.JsonMappingException; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.sun.jersey.api.client.Client; +import com.sun.jersey.api.client.ClientHandlerException; +import com.sun.jersey.api.client.ClientResponse; +import com.sun.jersey.api.client.UniformInterfaceException; +import com.sun.jersey.api.client.WebResource; +import com.sun.jersey.api.client.config.ClientConfig; +import com.sun.jersey.api.client.config.DefaultClientConfig; +import com.sun.jersey.api.json.JSONConfiguration; +import com.sun.jersey.client.urlconnection.HTTPSProperties; +import com.sun.jersey.client.urlconnection.HttpURLConnectionFactory; +import com.sun.jersey.client.urlconnection.URLConnectionClientHandler; + +public final class NexusExecutorClient { + + private static final Logger LOGGER = Logger.getLogger(NexusExecutorClient.class); + + private final Client client; + private final String baseurl; + private final HostnameVerifier hostnameVerifier; + private final TrustManager[] trustAll; + + public NexusExecutorClient(String newBaseurl) { + this.baseurl = newBaseurl; + ClientConfig clientConfig = new DefaultClientConfig(); + clientConfig.getFeatures().put(JSONConfiguration.FEATURE_POJO_MAPPING, Boolean.TRUE); + client = new Client(new URLConnectionClientHandler(new HttpURLConnectionFactory() { + Proxy proxy = null; + + @Override + public HttpURLConnection getHttpURLConnection(URL url) throws IOException { + try { + String proxyIp = System.getenv("proxy_ip"); + String proxyPort = System.getenv("proxy_port"); + proxy = new Proxy(Proxy.Type.HTTP, new InetSocketAddress(proxyIp, Integer.parseInt(proxyPort))); + return (HttpURLConnection) url.openConnection(proxy); + } catch (NumberFormatException ex) { + return (HttpURLConnection) url.openConnection(); + } + } + }), clientConfig); + // Create all-trusting host name verifier + hostnameVerifier = new HostnameVerifier() { + @Override + public boolean verify(String hostname, SSLSession session) { + return true; + } + }; + // Create a trust manager that does not validate certificate chains + trustAll = new TrustManager[] {new X509TrustManager() { + @Override + public X509Certificate[] getAcceptedIssuers() { + return null; // Not relevant. + } + + @Override + public void checkClientTrusted(X509Certificate[] certs, String authType) { + // Do nothing. Just allow them all. + } + + @Override + public void checkServerTrusted(X509Certificate[] certs, String authType) { + // Do nothing. Just allow them all. + } + }}; + } + + public String getBaseUrl() { + return this.baseurl; + } + + public List getRobotTestResults() throws ClientHandlerException, UniformInterfaceException, + JsonParseException, JsonMappingException, IOException, KeyManagementException, NoSuchAlgorithmException { + List robotTestResults = new ArrayList(); + LOGGER.info("Trying to get Robot Test Results"); + setProperties(); + WebResource webResource = this.client.resource(this.baseurl + "/"); + LOGGER.debug("Request URI of get: " + webResource.getURI().toString()); + ClientResponse response = webResource.get(ClientResponse.class); + if (response.getStatus() != 200) { + throw new HttpException("Could not retrieve robot test results from Nexus. HTTP error code : " + + response.getStatus() + " and message: " + response.getEntity(String.class)); + } + Document document = Jsoup.parse(response.getEntity(String.class)); + List elements = + document.getElementsByTag("body").get(0).getElementsByTag("table").get(0).getElementsByTag("tr"); + for (int i = 2; i < elements.size(); i++) { + String resultName = elements.get(i).getElementsByTag("td").get(0).getElementsByTag("a").get(0).text(); + resultName = resultName.substring(0, resultName.length() - 1); + webResource = this.client.resource(this.baseurl + "/" + resultName + "/output.xml"); + LOGGER.debug("Request URI of get: " + webResource.getURI().toString()); + response = webResource.get(ClientResponse.class); + if (response.getStatus() != 200) { + throw new HttpException("Could not retrieve robot test result from Nexus. HTTP error code : " + + response.getStatus() + " and message: " + response.getEntity(String.class)); + } + String result = response.getEntity(String.class); + JSONObject xmlJSONObj = XML.toJSONObject(result); + ObjectMapper mapper = new ObjectMapper(); + mapper.disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES); + RobotTestResult robotTestResult = mapper.readValue(xmlJSONObj.toString(), RobotTestResult.class); + robotTestResult.setName(resultName); + robotTestResults.add(robotTestResult); + } + return robotTestResults; + } + + private void setProperties() throws NoSuchAlgorithmException, KeyManagementException { + SSLContext sslContext = SSLContext.getInstance("SSL"); + sslContext.init(null, this.trustAll, new java.security.SecureRandom()); + HttpsURLConnection.setDefaultSSLSocketFactory(sslContext.getSocketFactory()); + // Install the all-trusting host verifier + HttpsURLConnection.setDefaultHostnameVerifier(this.hostnameVerifier); + DefaultClientConfig config = new DefaultClientConfig(); + Map properties = config.getProperties(); + HTTPSProperties httpsProperties = new HTTPSProperties((str, sslSession) -> true, sslContext); + properties.put(HTTPSProperties.PROPERTY_HTTPS_PROPERTIES, httpsProperties); + } + +} diff --git a/ui/src/main/java/org/akraino/validation/ui/client/nexus/resources/IResource.java b/ui/src/main/java/org/akraino/validation/ui/client/nexus/resources/IResource.java new file mode 100644 index 0000000..2cfe00b --- /dev/null +++ b/ui/src/main/java/org/akraino/validation/ui/client/nexus/resources/IResource.java @@ -0,0 +1,20 @@ +/* + * Copyright (c) 2019 AT&T Intellectual Property. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.akraino.validation.ui.client.nexus.resources; + +public interface IResource { + +} diff --git a/ui/src/main/java/org/akraino/validation/ui/client/nexus/resources/RobotTestResult.java b/ui/src/main/java/org/akraino/validation/ui/client/nexus/resources/RobotTestResult.java new file mode 100644 index 0000000..44ddc56 --- /dev/null +++ b/ui/src/main/java/org/akraino/validation/ui/client/nexus/resources/RobotTestResult.java @@ -0,0 +1,283 @@ +/* + * Copyright (c) 2019 AT&T Intellectual Property. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. You may obtain + * a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + * implied. See the License for the specific language governing + * permissions and limitations under the License. + */ +package org.akraino.validation.ui.client.nexus.resources; + +import java.util.List; + +import org.codehaus.jackson.annotate.JsonIgnoreProperties; +import org.codehaus.jackson.annotate.JsonProperty; +import org.codehaus.jackson.map.annotate.JsonSerialize; + +@JsonIgnoreProperties(ignoreUnknown = true) +@JsonSerialize(include = JsonSerialize.Inclusion.NON_NULL) +public class RobotTestResult implements IResource { + + @JsonProperty("robot") + private Robot robot; + + private String name; + + public RobotTestResult() { + + } + + public Robot getRobot() { + return this.robot; + } + + public void setRobot(Robot robot) { + this.robot = robot; + } + + public String getName() { + return this.name; + } + + public void setName(String name) { + this.name = name; + } + + public class Robot { + @JsonProperty("suite") + private Suite suite; + + @JsonProperty("statistics") + private Statistics statistics; + + @JsonProperty("generated") + private String generated; + + @JsonProperty("generator") + private String generator; + + @JsonProperty("errors") + private String errors; + + public Robot() { + + } + + public Suite getSuite() { + return this.suite; + } + + public void setSuite(Suite suite) { + this.suite = suite; + } + + public Statistics getStatistics() { + return this.statistics; + } + + public void setStatistics(Statistics statistics) { + this.statistics = statistics; + } + + public String getGenerated() { + return this.generated; + } + + public void setGenerated(String generated) { + this.generated = generated; + } + + public String getGenerator() { + return this.generator; + } + + public void setGenerator(String generator) { + this.generator = generator; + } + + public String getErrors() { + return this.errors; + } + + public void setErrors(String errors) { + this.errors = errors; + } + + public class Suite { + @JsonProperty("status") + private Suite.Status status; + + @JsonProperty("_id") + private String suiteId; + + @JsonProperty("_name") + private String name; + + public Suite() { + + } + + public String getSuiteId() { + return this.suiteId; + } + + public void setSuiteId(String suiteId) { + this.suiteId = suiteId; + } + + public String getName() { + return this.name; + } + + public void setName(String name) { + this.name = name; + } + + public Suite.Status getStatus() { + return this.status; + } + + public void setStatus(Suite.Status status) { + this.status = status; + } + + public class Status { + @JsonProperty("_status") + private String statusValue; + + @JsonProperty("_starttime") + private String startTime; + + @JsonProperty("_endtime") + private String endTime; + + public Status() { + + } + + public String getStatusValue() { + return this.statusValue; + } + + public void setStatusValue(String statusValue) { + this.statusValue = statusValue; + } + + public String getStartTime() { + return this.startTime; + } + + public void setStartTime(String startTime) { + this.startTime = startTime; + } + + public String getEndTime() { + return this.endTime; + } + + public void setEndTime(String endTime) { + this.endTime = endTime; + } + } + + } + + public class Statistics { + @JsonProperty("suite") + private Suite suite; + + @JsonProperty("total") + private Total total; + + @JsonProperty("tag") + private TagStat tag; + + public Statistics() { + + } + + public Suite getSuite() { + return this.suite; + } + + public void setSuite(Suite suite) { + this.suite = suite; + } + + public Total getTotal() { + return this.total; + } + + public void setTotal(Total total) { + this.total = total; + } + + public TagStat getTag() { + return this.tag; + } + + public void setTag(TagStat tag) { + this.tag = tag; + } + + public class Suite { + @JsonProperty("stat") + private List stat; + + public Suite() { + + } + + public List getStat() { + return this.stat; + } + + public void setStat(List stat) { + this.stat = stat; + } + } + + public class Total { + @JsonProperty("stat") + private List stat; + + public Total() { + + } + + public List getStat() { + return this.stat; + } + + public void setStat(List stat) { + this.stat = stat; + } + } + + public class TagStat { + @JsonProperty("stat") + private List stat; + + public TagStat() { + + } + + public List getStat() { + return this.stat; + } + + public void setStat(List stat) { + this.stat = stat; + } + } + } + } + +} diff --git a/ui/src/main/java/org/akraino/validation/ui/client/nexus/resources/Status.java b/ui/src/main/java/org/akraino/validation/ui/client/nexus/resources/Status.java new file mode 100644 index 0000000..07639f2 --- /dev/null +++ b/ui/src/main/java/org/akraino/validation/ui/client/nexus/resources/Status.java @@ -0,0 +1,72 @@ +/* + * Copyright (c) 2019 AT&T Intellectual Property. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.akraino.validation.ui.client.nexus.resources; + +import org.codehaus.jackson.annotate.JsonIgnoreProperties; +import org.codehaus.jackson.annotate.JsonProperty; +import org.codehaus.jackson.map.annotate.JsonSerialize; + +@JsonIgnoreProperties(ignoreUnknown = true) +@JsonSerialize(include = JsonSerialize.Inclusion.NON_NULL) +public class Status { + @JsonProperty("fail") + private int fail; + + @JsonProperty("pass") + private int pass; + + @JsonProperty("name") + private String name; + + @JsonProperty("content") + private String content; + + public Status() { + + } + + public int getFail() { + return this.fail; + } + + public void setFail(int fail) { + this.fail = fail; + } + + public int getPass() { + return this.pass; + } + + public void setPass(int pass) { + this.pass = pass; + } + + public String getName() { + return this.name; + } + + public void setName(String name) { + this.name = name; + } + + public String getContent() { + return this.content; + } + + public void setContent(String content) { + this.content = content; + } +} diff --git a/ui/src/main/java/org/akraino/validation/ui/common/PropertyUtil.java b/ui/src/main/java/org/akraino/validation/ui/common/PropertyUtil.java new file mode 100644 index 0000000..d0e46b2 --- /dev/null +++ b/ui/src/main/java/org/akraino/validation/ui/common/PropertyUtil.java @@ -0,0 +1,77 @@ +/* + * Copyright (c) 2019 AT&T Intellectual Property. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.akraino.validation.ui.common; + +import java.io.IOException; +import java.io.InputStream; +import java.util.Properties; + +import org.akraino.validation.ui.config.AppConfig; +import org.apache.log4j.Logger; + +public class PropertyUtil { + private static final Logger LOGGER = Logger.getLogger(PropertyUtil.class); + private static final String PROP_FILENAME = "app.properties"; + private static PropertyUtil instance; + + private Properties appProps; + + /** + * Return the single instance of this object in the app. + * + * @return the singleton + */ + public static synchronized PropertyUtil getInstance() { + if (instance == null) { + instance = new PropertyUtil(); + } + return instance; + } + + private PropertyUtil() { + InputStream input = AppConfig.class.getClassLoader().getResourceAsStream(PROP_FILENAME); + appProps = new Properties(); + try { + appProps.load(input); + } catch (IOException e) { + LOGGER.error("Error loading properties file: " + PROP_FILENAME); + } finally { + try { + input.close(); + } catch (IOException e) { + // ignore + } + } + } + + /** + * Get a property from the PropertyUtil object. If the environment variable $IP is set, then any URL's referring to + * localhost will be rewritten to use this IP address instead. + * + * @param key the key to use to find the property + * @return the value + */ + public String getProperty(String key) { + String property = appProps.getProperty(key); + if (property != null && property.indexOf("://localhost:") > 0) { + String ipAddr = System.getenv().get("IP"); + if (ipAddr != null && !"".contentEquals(ipAddr)) { + property = property.replaceAll("://localhost:", "://" + ipAddr + ":"); + } + } + return property; + } +} diff --git a/ui/src/main/java/org/akraino/validation/ui/common/ServiceInitializationListener.java b/ui/src/main/java/org/akraino/validation/ui/common/ServiceInitializationListener.java new file mode 100644 index 0000000..e4836ad --- /dev/null +++ b/ui/src/main/java/org/akraino/validation/ui/common/ServiceInitializationListener.java @@ -0,0 +1,30 @@ +/* + * Copyright (c) 2019 AT&T Intellectual Property. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.akraino.validation.ui.common; + +import org.springframework.context.ApplicationListener; +import org.springframework.context.event.ContextRefreshedEvent; +import org.springframework.stereotype.Component; + +@Component +public class ServiceInitializationListener implements ApplicationListener { + + @Override + public void onApplicationEvent(ContextRefreshedEvent event) { + + } + +} diff --git a/ui/src/main/java/org/akraino/validation/ui/common/SessionManagerFilter.java b/ui/src/main/java/org/akraino/validation/ui/common/SessionManagerFilter.java new file mode 100644 index 0000000..e0ddd91 --- /dev/null +++ b/ui/src/main/java/org/akraino/validation/ui/common/SessionManagerFilter.java @@ -0,0 +1,77 @@ +/* + * Copyright (c) 2019 AT&T Intellectual Property. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.akraino.validation.ui.common; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import org.apache.log4j.Logger; +import org.springframework.web.servlet.HandlerInterceptor; +import org.springframework.web.servlet.ModelAndView; + +public class SessionManagerFilter implements HandlerInterceptor { + + private static final Logger LOGGER = Logger.getLogger(SessionManagerFilter.class); + + @Override + public void afterCompletion(HttpServletRequest arg0, HttpServletResponse arg1, Object arg2, Exception arg3) + throws Exception { + + LOGGER.info("user authenticated"); + + } + + @Override + public void postHandle(HttpServletRequest arg0, HttpServletResponse arg1, Object arg2, ModelAndView arg3) + throws Exception { + + LOGGER.info("user authenticated"); + + } + + @Override + public boolean preHandle(HttpServletRequest req, HttpServletResponse res, Object data) throws Exception { + + try { + return true; + /* + * if (StringUtil.notEmpty(req.getHeader("tokenId"))) { + * + * String clientToken = req.getHeader("tokenId"); + * + * AccessService service = new AccessService(); + * + * UserSession user = service.getUserSession(LoginUtil.decode(LoginUtil.getUserName(clientToken))); + * + * if (user.getTokenId()!= null && !sessionExpired(user)) { + * + * if (user.getTokenId().equals(LoginUtil.getPassword(clientToken))) { // user authorized return true; + * + * } else { // unauthorized access res.sendError(401); } } else { // session does not exist/expired, + * temporary re-direct, ask user to re-login res.sendError(307); } + * + * } else { // bad request, no authToken sent in the request res.sendError(400); } + */ + } catch (Exception e) { + LOGGER.error(e); + } + + + return false; + } + + +} diff --git a/ui/src/main/java/org/akraino/validation/ui/config/AppConfig.java b/ui/src/main/java/org/akraino/validation/ui/config/AppConfig.java new file mode 100644 index 0000000..6d55d42 --- /dev/null +++ b/ui/src/main/java/org/akraino/validation/ui/config/AppConfig.java @@ -0,0 +1,74 @@ +/* + * Copyright (c) 2019 AT&T Intellectual Property. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.akraino.validation.ui.config; + +import javax.sql.DataSource; + +import org.akraino.validation.ui.common.PropertyUtil; +import org.akraino.validation.ui.common.SessionManagerFilter; +import org.apache.commons.dbcp.BasicDataSource; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.ComponentScan; +import org.springframework.context.annotation.Configuration; +import org.springframework.web.multipart.commons.CommonsMultipartResolver; +import org.springframework.web.servlet.config.annotation.DefaultServletHandlerConfigurer; +import org.springframework.web.servlet.config.annotation.EnableWebMvc; +import org.springframework.web.servlet.config.annotation.InterceptorRegistry; +import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter; + +@Configuration +@EnableWebMvc +@ComponentScan(basePackages = "org.akraino.validation.ui") +public class AppConfig extends WebMvcConfigurerAdapter { + + @Bean + SessionManagerFilter getSessionManager() { + return new SessionManagerFilter(); + } + + @Override + public void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) { + configurer.enable(); + } + + @Override + public void addInterceptors(InterceptorRegistry registry) { + registry.addInterceptor(getSessionManager()).addPathPatterns("/**").excludePathPatterns("/login", "/logout"); + + } + + @Bean + public CommonsMultipartResolver multipartResolver() { + + CommonsMultipartResolver cmr = new CommonsMultipartResolver(); + cmr.setMaxUploadSize(1000000 * 2); + cmr.setMaxUploadSizePerFile(2000000); // bytes + return cmr; + + } + + @Bean(name = "dataSource") + public DataSource getDataSource() { + BasicDataSource dataSource = new BasicDataSource(); + dataSource.setDriverClassName("org.postgresql.Driver"); + dataSource.setUrl(PropertyUtil.getInstance().getProperty("postgres.db.url")); + dataSource.setUsername(PropertyUtil.getInstance().getProperty("postgres.db.user.name")); + dataSource.setPassword(System.getenv("postgres_db_user_pwd")); + + return dataSource; + } + +} diff --git a/ui/src/main/java/org/akraino/validation/ui/config/AppInitializer.java b/ui/src/main/java/org/akraino/validation/ui/config/AppInitializer.java new file mode 100644 index 0000000..d79b2ae --- /dev/null +++ b/ui/src/main/java/org/akraino/validation/ui/config/AppInitializer.java @@ -0,0 +1,85 @@ +/* + * Copyright (c) 2019 AT&T Intellectual Property. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.akraino.validation.ui.config; + +import java.lang.reflect.Field; +import java.util.Comparator; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.PriorityBlockingQueue; +import java.util.concurrent.ThreadPoolExecutor; +import java.util.concurrent.TimeUnit; + +import javax.servlet.ServletContext; +import javax.servlet.ServletException; +import javax.servlet.ServletRegistration; + +import org.springframework.web.WebApplicationInitializer; +import org.springframework.web.context.support.AnnotationConfigWebApplicationContext; +import org.springframework.web.servlet.DispatcherServlet; + +public class AppInitializer implements WebApplicationInitializer { + + private static final int QUEUE_CAPACITY = 500; + private static final int EXECUTOR_SIZE = 20; // the number of threads to keep in the pool, even if + // they are idle, unless allowCoreThreadTimeOut is + // set + private static final int EXECUTOR_MAX_SIZE = 20; // the maximum number of threads to allow in the pool + private static final int KEEPALIVE_TIME = 20; // when the number of threads is greater than the + // core, this is the maximum time that excess idle + // threads will wait for new tasks before + // terminating. + private static final PriorityBlockingQueue BLOCKING_QUEUE = + new PriorityBlockingQueue(QUEUE_CAPACITY, new CFRunnableComparator()); + public static ExecutorService executorService = new ThreadPoolExecutor(EXECUTOR_SIZE, + EXECUTOR_MAX_SIZE, KEEPALIVE_TIME, TimeUnit.SECONDS, BLOCKING_QUEUE); + + @Override + public void onStartup(ServletContext container) throws ServletException { + + AnnotationConfigWebApplicationContext ctx = new AnnotationConfigWebApplicationContext(); + ctx.register(AppConfig.class); + ctx.setServletContext(container); + + ServletRegistration.Dynamic servlet = container.addServlet("dispatcher", new DispatcherServlet(ctx)); + + servlet.setLoadOnStartup(1); + servlet.addMapping("/"); + + } + + private static class CFRunnableComparator implements Comparator { + @Override + @SuppressWarnings("unchecked") + public int compare(Runnable runnable1, Runnable runnable2) { + // T might be AsyncSupply, UniApply, etc., but we want to + // compare our original Runnables. + return ((Comparable) unwrap(runnable1)).compareTo(unwrap(runnable2)); + } + + private Object unwrap(Runnable runnable) { + try { + Field field = runnable.getClass().getDeclaredField("fn"); + field.setAccessible(true); + // NB: For performance-intensive contexts, you may want to + // cache these in a ConcurrentHashMap, Field>. + return field.get(runnable); + } catch (IllegalAccessException | NoSuchFieldException e) { + throw new IllegalArgumentException("Couldn't unwrap " + runnable, e); + } + } + } + +} diff --git a/ui/src/main/java/org/akraino/validation/ui/config/HibernateConfig.java b/ui/src/main/java/org/akraino/validation/ui/config/HibernateConfig.java new file mode 100644 index 0000000..03a91be --- /dev/null +++ b/ui/src/main/java/org/akraino/validation/ui/config/HibernateConfig.java @@ -0,0 +1,75 @@ +/* + * Copyright (c) 2019 AT&T Intellectual Property. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.akraino.validation.ui.config; + +import java.util.Properties; + +import javax.sql.DataSource; + +import org.hibernate.SessionFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.PropertySource; +import org.springframework.core.env.Environment; +import org.springframework.orm.hibernate5.HibernateTransactionManager; +import org.springframework.orm.hibernate5.LocalSessionFactoryBuilder; +import org.springframework.transaction.annotation.EnableTransactionManagement; + +@Configuration +@EnableTransactionManagement +@PropertySource(value = {"classpath:hibernate.properties"}) +public class HibernateConfig { + + @Autowired + private Environment env; + + @Autowired + @Bean(name = "sessionFactory") + public SessionFactory getSessionFactory(DataSource dataSource) { + LocalSessionFactoryBuilder sessionBuilder = new LocalSessionFactoryBuilder(dataSource); + + sessionBuilder.scanPackages("org.akraino.validation.ui.entity"); + sessionBuilder.addProperties(hibernateProperties()); + + return sessionBuilder.buildSessionFactory(); + + } + + @Autowired + @Bean(name = "transactionManager") + public HibernateTransactionManager getTransactionManager(SessionFactory sessionFactory) { + + return new HibernateTransactionManager(sessionFactory); + + } + + private Properties hibernateProperties() { + + Properties properties = new Properties(); + + properties.put("hibernate.dialect", env.getProperty("hibernate.dialect")); + properties.put("hibernate.show_sql", env.getProperty("hibernate.show_sql")); + properties.put("hibernate.c3p0.min_size", env.getProperty("hibernate.c3p0.min_size")); + properties.put("hibernate.c3p0.max_size", env.getProperty("hibernate.c3p0.max_size")); + properties.put("hibernate.c3p0.max_statements", env.getProperty("hibernate.c3p0.max_statements")); + properties.put("hibernate.c3p0.acquire_increment", env.getProperty("hibernate.c3p0.acquire_increment")); + properties.put("hibernate.jdbc.use_streams_for_binary", + env.getProperty("hibernate.jdbc.use_streams_for_binary")); + + return properties; + } +} diff --git a/ui/src/main/java/org/akraino/validation/ui/controller/BlueprintController.java b/ui/src/main/java/org/akraino/validation/ui/controller/BlueprintController.java new file mode 100644 index 0000000..22ae510 --- /dev/null +++ b/ui/src/main/java/org/akraino/validation/ui/controller/BlueprintController.java @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2019 AT&T Intellectual Property. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. You may obtain + * a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + * implied. See the License for the specific language governing + * permissions and limitations under the License. + */ +package org.akraino.validation.ui.controller; + +import java.util.List; + +import org.akraino.validation.ui.entity.Blueprint; +import org.akraino.validation.ui.service.BlueprintService; +import org.apache.log4j.Logger; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +@RestController +@RequestMapping("/api/blueprint") +public class BlueprintController { + + @Autowired + BlueprintService service; + + private static final Logger LOGGER = Logger.getLogger(BlueprintController.class); + + @GetMapping("/") + public ResponseEntity> getBlueprints() { + try { + return new ResponseEntity<>(service.getBlueprints(), HttpStatus.OK); + } catch (Exception e) { + LOGGER.error(e); + } + return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(null); + } + +} diff --git a/ui/src/main/java/org/akraino/validation/ui/controller/BlueprintInstanceController.java b/ui/src/main/java/org/akraino/validation/ui/controller/BlueprintInstanceController.java new file mode 100644 index 0000000..6acdba8 --- /dev/null +++ b/ui/src/main/java/org/akraino/validation/ui/controller/BlueprintInstanceController.java @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2019 AT&T Intellectual Property. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. You may obtain + * a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + * implied. See the License for the specific language governing + * permissions and limitations under the License. + */ +package org.akraino.validation.ui.controller; + +import java.util.List; + +import org.akraino.validation.ui.entity.BlueprintInstance; +import org.akraino.validation.ui.service.BlueprintInstanceService; +import org.apache.log4j.Logger; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +@RestController +@RequestMapping("/api/blueprintInstance") +public class BlueprintInstanceController { + + @Autowired + BlueprintInstanceService service; + + private static final Logger LOGGER = Logger.getLogger(BlueprintInstanceController.class); + + @GetMapping("/") + public ResponseEntity> getBlueprintInstances() { + try { + return new ResponseEntity<>(service.getBlueprintInstances(), HttpStatus.OK); + } catch (Exception e) { + LOGGER.error(e); + } + return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(null); + } + +} diff --git a/ui/src/main/java/org/akraino/validation/ui/controller/JenkinsJobNotificationController.java b/ui/src/main/java/org/akraino/validation/ui/controller/JenkinsJobNotificationController.java new file mode 100644 index 0000000..1c0b3bc --- /dev/null +++ b/ui/src/main/java/org/akraino/validation/ui/controller/JenkinsJobNotificationController.java @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2019 AT&T Intellectual Property. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.akraino.validation.ui.controller; + +import org.akraino.validation.ui.data.JnksJobNotify; +import org.akraino.validation.ui.service.JenkinsJobNotificationService; +import org.apache.log4j.Logger; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +@RestController +@RequestMapping("/api/jenkinsJobNotification") +public class JenkinsJobNotificationController { + + @Autowired + JenkinsJobNotificationService service; + + private static final Logger LOGGER = Logger.getLogger(JenkinsJobNotificationController.class); + + @PostMapping("/") + public ResponseEntity handle(@RequestBody JnksJobNotify jnksJobNotify) { + try { + service.handle(jnksJobNotify); + return new ResponseEntity(HttpStatus.OK); + } catch (Exception e) { + LOGGER.error(e); + } + return new ResponseEntity(HttpStatus.INTERNAL_SERVER_ERROR); + } + +} diff --git a/ui/src/main/java/org/akraino/validation/ui/controller/ResultsController.java b/ui/src/main/java/org/akraino/validation/ui/controller/ResultsController.java new file mode 100644 index 0000000..3013948 --- /dev/null +++ b/ui/src/main/java/org/akraino/validation/ui/controller/ResultsController.java @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2019 AT&T Intellectual Property. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.akraino.validation.ui.controller; + +import java.util.List; + +import org.akraino.validation.ui.client.nexus.resources.RobotTestResult; +import org.akraino.validation.ui.service.ResultService; +import org.apache.log4j.Logger; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +@RestController +@RequestMapping("/api/results") +public class ResultsController { + + private static final Logger LOGGER = Logger.getLogger(ResultsController.class); + + @Autowired + ResultService service; + + @RequestMapping(value = "/findBySubmissionId/{id}") + public ResponseEntity> findByBlueprintId(@PathVariable("id") String submissionId) { + try { + return new ResponseEntity<>(service.getRobotTestResults(submissionId), HttpStatus.OK); + } catch (Exception e) { + LOGGER.error(e); + } + return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(null); + } + +} diff --git a/ui/src/main/java/org/akraino/validation/ui/controller/SubmissionController.java b/ui/src/main/java/org/akraino/validation/ui/controller/SubmissionController.java new file mode 100644 index 0000000..ca78b0d --- /dev/null +++ b/ui/src/main/java/org/akraino/validation/ui/controller/SubmissionController.java @@ -0,0 +1,73 @@ +/* + * Copyright (c) 2019 AT&T Intellectual Property. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.akraino.validation.ui.controller; + +import java.util.List; + +import org.akraino.validation.ui.entity.Submission; +import org.akraino.validation.ui.service.SubmissionService; +import org.apache.log4j.Logger; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.DeleteMapping; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +@RestController +@RequestMapping("/api/submission") +public class SubmissionController { + + @Autowired + SubmissionService service; + + private static final Logger LOGGER = Logger.getLogger(SubmissionController.class); + + @GetMapping("/") + public ResponseEntity> getSubmissions() { + try { + return new ResponseEntity<>(service.getSubmissions(), HttpStatus.OK); + } catch (Exception e) { + LOGGER.error(e); + } + return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(null); + } + + @PostMapping("/") + public ResponseEntity postSubmission(@RequestBody Submission newSubmission) { + try { + return new ResponseEntity<>(service.saveSubmission(newSubmission), HttpStatus.CREATED); + } catch (Exception e) { + LOGGER.error(e); + } + return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(null); + } + + @DeleteMapping("/") + public ResponseEntity deleteSubmission(@RequestBody Submission submission) { + try { + service.deleteSubmission(submission.getSubmissionId()); + return new ResponseEntity<>(true, HttpStatus.OK); + } catch (Exception e) { + LOGGER.error(e); + } + return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(false); + } + +} diff --git a/ui/src/main/java/org/akraino/validation/ui/controller/TimeSlotsController.java b/ui/src/main/java/org/akraino/validation/ui/controller/TimeSlotsController.java new file mode 100644 index 0000000..d6da8a9 --- /dev/null +++ b/ui/src/main/java/org/akraino/validation/ui/controller/TimeSlotsController.java @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2019 AT&T Intellectual Property. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.akraino.validation.ui.controller; + +import java.util.List; + +import org.akraino.validation.ui.entity.Timeslot; +import org.akraino.validation.ui.service.TimeslotService; +import org.apache.log4j.Logger; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +@RestController +@RequestMapping("/api/timeslots") +public class TimeSlotsController { + + @Autowired + TimeslotService service; + + private static final Logger LOGGER = Logger.getLogger(TimeSlotsController.class); + + @GetMapping("/") + public ResponseEntity> getTimeSlots() { + try { + return new ResponseEntity<>(service.getTimeslots(), HttpStatus.OK); + } catch (Exception e) { + LOGGER.error(e); + } + return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(null); + } + +} diff --git a/ui/src/main/java/org/akraino/validation/ui/dao/BlueprintDAO.java b/ui/src/main/java/org/akraino/validation/ui/dao/BlueprintDAO.java new file mode 100644 index 0000000..537d298 --- /dev/null +++ b/ui/src/main/java/org/akraino/validation/ui/dao/BlueprintDAO.java @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2019 AT&T Intellectual Property. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. You may obtain + * a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + * implied. See the License for the specific language governing + * permissions and limitations under the License. + */ +package org.akraino.validation.ui.dao; + +import java.util.List; + +import org.akraino.validation.ui.entity.Blueprint; + +public interface BlueprintDAO { + + void saveOrUpdate(Blueprint blueprint); + + void merge(Blueprint blueprint); + + List getBlueprints(); + + Blueprint getBlueprint(Integer blueprintId); + + void deleteBlueprint(Blueprint blueprint); + + void deleteAll(); + +} diff --git a/ui/src/main/java/org/akraino/validation/ui/dao/BlueprintInstanceDAO.java b/ui/src/main/java/org/akraino/validation/ui/dao/BlueprintInstanceDAO.java new file mode 100644 index 0000000..5093681 --- /dev/null +++ b/ui/src/main/java/org/akraino/validation/ui/dao/BlueprintInstanceDAO.java @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2019 AT&T Intellectual Property. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. You may obtain + * a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + * implied. See the License for the specific language governing + * permissions and limitations under the License. + */ +package org.akraino.validation.ui.dao; + +import java.util.List; + +import org.akraino.validation.ui.entity.BlueprintInstance; + +public interface BlueprintInstanceDAO { + + void saveOrUpdate(BlueprintInstance blueprintInstance); + + void merge(BlueprintInstance blueprintInstance); + + List getBlueprintInstances(); + + BlueprintInstance getBlueprintInstance(Integer instId); + + void deleteBlueprintInstance(BlueprintInstance blueprintInstance); + + void deleteAll(); + +} diff --git a/ui/src/main/java/org/akraino/validation/ui/dao/SubmissionDAO.java b/ui/src/main/java/org/akraino/validation/ui/dao/SubmissionDAO.java new file mode 100644 index 0000000..fc5e84f --- /dev/null +++ b/ui/src/main/java/org/akraino/validation/ui/dao/SubmissionDAO.java @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2019 AT&T Intellectual Property. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + */ +package org.akraino.validation.ui.dao; + +import java.util.List; + +import org.akraino.validation.ui.entity.Submission; + +public interface SubmissionDAO { + + void saveOrUpdate(Submission submission); + + void merge(Submission submission); + + List getSubmissions(); + + Submission getSubmission(Integer submissionId); + + void deleteSubmission(Submission submission); + + void deleteSubmission(Integer submissionId); + + void deleteAll(); + +} diff --git a/ui/src/main/java/org/akraino/validation/ui/dao/TimeslotDAO.java b/ui/src/main/java/org/akraino/validation/ui/dao/TimeslotDAO.java new file mode 100644 index 0000000..c4dbbe1 --- /dev/null +++ b/ui/src/main/java/org/akraino/validation/ui/dao/TimeslotDAO.java @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2019 AT&T Intellectual Property. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.akraino.validation.ui.dao; + +import java.util.List; + +import org.akraino.validation.ui.entity.Timeslot; + +public interface TimeslotDAO { + + void saveOrUpdate(Timeslot timeslot); + + void merge(Timeslot timeslot); + + List getTimeslots(); + + Timeslot getTimeslot(Integer timeslotId); + + void deleteTimeslot(Timeslot timeslot); + + void deleteAll(); + +} diff --git a/ui/src/main/java/org/akraino/validation/ui/daoimpl/BlueprintDAOImpl.java b/ui/src/main/java/org/akraino/validation/ui/daoimpl/BlueprintDAOImpl.java new file mode 100644 index 0000000..5466c13 --- /dev/null +++ b/ui/src/main/java/org/akraino/validation/ui/daoimpl/BlueprintDAOImpl.java @@ -0,0 +1,99 @@ +/* + * Copyright (c) 2019 AT&T Intellectual Property. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.akraino.validation.ui.daoimpl; + +import java.util.List; + +import javax.persistence.EntityManager; +import javax.persistence.criteria.CriteriaBuilder; +import javax.persistence.criteria.CriteriaQuery; +import javax.persistence.criteria.Root; + +import org.akraino.validation.ui.dao.BlueprintDAO; +import org.akraino.validation.ui.entity.Blueprint; +import org.apache.log4j.Logger; +import org.hibernate.Session; +import org.hibernate.SessionFactory; +import org.hibernate.query.Query; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Repository; + +@Repository +public class BlueprintDAOImpl implements BlueprintDAO { + + private static final Logger LOGGER = Logger.getLogger(BlueprintDAOImpl.class); + + @Autowired + private SessionFactory sessionFactory; + + protected Session getSession() { + return sessionFactory.getCurrentSession(); + } + + @Override + public List getBlueprints() { + + CriteriaBuilder builder = getSession().getCriteriaBuilder(); + CriteriaQuery criteria = builder.createQuery(Blueprint.class); + + Root root = criteria.from(Blueprint.class); + criteria.select(root); + + Query query = getSession().createQuery(criteria); + + return query.getResultList(); + + } + + @Override + public Blueprint getBlueprint(Integer blueprintId) { + + EntityManager entityManager = getSession().getEntityManagerFactory().createEntityManager(); + + return entityManager.find(Blueprint.class, blueprintId); + } + + @Override + public void saveOrUpdate(Blueprint blueprint) { + getSession().saveOrUpdate(blueprint); + + } + + @Override + public void merge(Blueprint blueprint) { + getSession().merge(blueprint); + + } + + @Override + public void deleteBlueprint(Blueprint blueprint) { + getSession().delete(blueprint); + + } + + @Override + public void deleteAll() { + + Query query = getSession().createQuery("delete from Blueprint"); + + int result = query.executeUpdate(); + + if (result > 0) { + LOGGER.info("All blueprint entries are cleaned up"); + } + } + +} diff --git a/ui/src/main/java/org/akraino/validation/ui/daoimpl/BlueprintInstanceDAOImpl.java b/ui/src/main/java/org/akraino/validation/ui/daoimpl/BlueprintInstanceDAOImpl.java new file mode 100644 index 0000000..4bacb14 --- /dev/null +++ b/ui/src/main/java/org/akraino/validation/ui/daoimpl/BlueprintInstanceDAOImpl.java @@ -0,0 +1,99 @@ +/* + * Copyright (c) 2019 AT&T Intellectual Property. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.akraino.validation.ui.daoimpl; + +import java.util.List; + +import javax.persistence.EntityManager; +import javax.persistence.criteria.CriteriaBuilder; +import javax.persistence.criteria.CriteriaQuery; +import javax.persistence.criteria.Root; + +import org.akraino.validation.ui.dao.BlueprintInstanceDAO; +import org.akraino.validation.ui.entity.BlueprintInstance; +import org.apache.log4j.Logger; +import org.hibernate.Session; +import org.hibernate.SessionFactory; +import org.hibernate.query.Query; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Repository; + +@Repository +public class BlueprintInstanceDAOImpl implements BlueprintInstanceDAO { + + private static final Logger LOGGER = Logger.getLogger(BlueprintInstanceDAOImpl.class); + + @Autowired + private SessionFactory sessionFactory; + + protected Session getSession() { + return sessionFactory.getCurrentSession(); + } + + @Override + public List getBlueprintInstances() { + + CriteriaBuilder builder = getSession().getCriteriaBuilder(); + CriteriaQuery criteria = builder.createQuery(BlueprintInstance.class); + + Root root = criteria.from(BlueprintInstance.class); + criteria.select(root); + + Query query = getSession().createQuery(criteria); + + return query.getResultList(); + + } + + @Override + public BlueprintInstance getBlueprintInstance(Integer instId) { + + EntityManager entityManager = getSession().getEntityManagerFactory().createEntityManager(); + + return entityManager.find(BlueprintInstance.class, instId); + } + + @Override + public void saveOrUpdate(BlueprintInstance blueprintInstance) { + getSession().saveOrUpdate(blueprintInstance); + + } + + @Override + public void merge(BlueprintInstance blueprintInstance) { + getSession().merge(blueprintInstance); + + } + + @Override + public void deleteBlueprintInstance(BlueprintInstance blueprintInstance) { + getSession().delete(blueprintInstance); + + } + + @Override + public void deleteAll() { + + Query query = getSession().createQuery("delete from BlueprintInstance"); + + int result = query.executeUpdate(); + + if (result > 0) { + LOGGER.info("All blueprint instance entries are cleaned up"); + } + } + +} diff --git a/ui/src/main/java/org/akraino/validation/ui/daoimpl/SubmissionDAOImpl.java b/ui/src/main/java/org/akraino/validation/ui/daoimpl/SubmissionDAOImpl.java new file mode 100644 index 0000000..fd4da86 --- /dev/null +++ b/ui/src/main/java/org/akraino/validation/ui/daoimpl/SubmissionDAOImpl.java @@ -0,0 +1,104 @@ +/* + * Copyright (c) 2019 AT&T Intellectual Property. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.akraino.validation.ui.daoimpl; + +import java.util.List; + +import javax.persistence.EntityManager; +import javax.persistence.criteria.CriteriaBuilder; +import javax.persistence.criteria.CriteriaQuery; +import javax.persistence.criteria.Root; + +import org.akraino.validation.ui.dao.SubmissionDAO; +import org.akraino.validation.ui.entity.Submission; +import org.apache.log4j.Logger; +import org.hibernate.Session; +import org.hibernate.SessionFactory; +import org.hibernate.query.Query; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Repository; + +@Repository +public class SubmissionDAOImpl implements SubmissionDAO { + + private static final Logger LOGGER = Logger.getLogger(SubmissionDAOImpl.class); + + @Autowired + private SessionFactory sessionFactory; + + protected Session getSession() { + return sessionFactory.getCurrentSession(); + } + + @Override + public List getSubmissions() { + + CriteriaBuilder builder = getSession().getCriteriaBuilder(); + CriteriaQuery criteria = builder.createQuery(Submission.class); + + Root root = criteria.from(Submission.class); + criteria.select(root); + + Query query = getSession().createQuery(criteria); + + return query.getResultList(); + + } + + @Override + public Submission getSubmission(Integer submissionId) { + + EntityManager entityManager = getSession().getEntityManagerFactory().createEntityManager(); + + return entityManager.find(Submission.class, submissionId); + } + + @Override + public void saveOrUpdate(Submission submission) { + getSession().saveOrUpdate(submission); + + } + + @Override + public void merge(Submission submission) { + getSession().merge(submission); + + } + + @Override + public void deleteSubmission(Submission submission) { + getSession().delete(submission); + + } + + @Override + public void deleteSubmission(Integer submissionId) { + getSession().delete(this.getSubmission(submissionId)); + } + + @Override + public void deleteAll() { + + Query query = getSession().createQuery("delete from Submission"); + + int result = query.executeUpdate(); + + if (result > 0) { + LOGGER.info("All submission entries are cleaned up"); + } + } + +} diff --git a/ui/src/main/java/org/akraino/validation/ui/daoimpl/TimeslotDAOImpl.java b/ui/src/main/java/org/akraino/validation/ui/daoimpl/TimeslotDAOImpl.java new file mode 100644 index 0000000..e49c37a --- /dev/null +++ b/ui/src/main/java/org/akraino/validation/ui/daoimpl/TimeslotDAOImpl.java @@ -0,0 +1,99 @@ +/* + * Copyright (c) 2019 AT&T Intellectual Property. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.akraino.validation.ui.daoimpl; + +import java.util.List; + +import javax.persistence.EntityManager; +import javax.persistence.criteria.CriteriaBuilder; +import javax.persistence.criteria.CriteriaQuery; +import javax.persistence.criteria.Root; + +import org.akraino.validation.ui.dao.TimeslotDAO; +import org.akraino.validation.ui.entity.Timeslot; +import org.apache.log4j.Logger; +import org.hibernate.Session; +import org.hibernate.SessionFactory; +import org.hibernate.query.Query; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Repository; + +@Repository +public class TimeslotDAOImpl implements TimeslotDAO { + + private static final Logger LOGGER = Logger.getLogger(TimeslotDAOImpl.class); + + @Autowired + private SessionFactory sessionFactory; + + protected Session getSession() { + return sessionFactory.getCurrentSession(); + } + + @Override + public List getTimeslots() { + + CriteriaBuilder builder = getSession().getCriteriaBuilder(); + CriteriaQuery criteria = builder.createQuery(Timeslot.class); + + Root root = criteria.from(Timeslot.class); + criteria.select(root); + + Query query = getSession().createQuery(criteria); + + return query.getResultList(); + + } + + @Override + public Timeslot getTimeslot(Integer timeslotId) { + + EntityManager entityManager = getSession().getEntityManagerFactory().createEntityManager(); + + return entityManager.find(Timeslot.class, timeslotId); + } + + @Override + public void saveOrUpdate(Timeslot timeslot) { + getSession().saveOrUpdate(timeslot); + + } + + @Override + public void merge(Timeslot timeslot) { + getSession().merge(timeslot); + + } + + @Override + public void deleteTimeslot(Timeslot timeslot) { + getSession().delete(timeslot); + + } + + @Override + public void deleteAll() { + + Query query = getSession().createQuery("delete from Timeslot"); + + int result = query.executeUpdate(); + + if (result > 0) { + LOGGER.info("All timeslot entries are cleaned up"); + } + } + +} diff --git a/ui/src/main/java/org/akraino/validation/ui/data/BlueprintLayer.java b/ui/src/main/java/org/akraino/validation/ui/data/BlueprintLayer.java new file mode 100644 index 0000000..75278c2 --- /dev/null +++ b/ui/src/main/java/org/akraino/validation/ui/data/BlueprintLayer.java @@ -0,0 +1,20 @@ +/* + * Copyright (c) 2019 AT&T Intellectual Property. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.akraino.validation.ui.data; + +public enum BlueprintLayer { + Hardware, OS, K8s, Kubeless, OpenStack, VNF, Application +} diff --git a/ui/src/main/java/org/akraino/validation/ui/data/JnksJobNotify.java b/ui/src/main/java/org/akraino/validation/ui/data/JnksJobNotify.java new file mode 100644 index 0000000..f72a307 --- /dev/null +++ b/ui/src/main/java/org/akraino/validation/ui/data/JnksJobNotify.java @@ -0,0 +1,63 @@ +/* + * Copyright (c) 2019 AT&T Intellectual Property. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.akraino.validation.ui.data; + +import org.codehaus.jackson.annotate.JsonIgnoreProperties; +import org.codehaus.jackson.annotate.JsonProperty; +import org.codehaus.jackson.map.annotate.JsonSerialize; + +@JsonIgnoreProperties(ignoreUnknown = true) +@JsonSerialize(include = JsonSerialize.Inclusion.NON_NULL) +public class JnksJobNotify { + + @JsonProperty("name") + private String name; + + @JsonProperty("buildNumber") + private Integer buildNumber; + + @JsonProperty("submissionId") + private Integer submissionId; + + public JnksJobNotify() { + + } + + public String getName() { + return this.name; + } + + public void setName(String name) { + this.name = name; + } + + public Integer getbuildNumber() { + return this.buildNumber; + } + + public void setbuildNumber(Integer buildNumber) { + this.buildNumber = buildNumber; + } + + public Integer getSubmissionId() { + return this.submissionId; + } + + public void setSubmissionId(Integer submissionId) { + this.submissionId = submissionId; + } + +} diff --git a/ui/src/main/java/org/akraino/validation/ui/data/Lab.java b/ui/src/main/java/org/akraino/validation/ui/data/Lab.java new file mode 100644 index 0000000..ae84d8e --- /dev/null +++ b/ui/src/main/java/org/akraino/validation/ui/data/Lab.java @@ -0,0 +1,20 @@ +/* + * Copyright (c) 2019 AT&T Intellectual Property. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.akraino.validation.ui.data; + +public enum Lab { + ATT, Ericsson, Community, Arm +} diff --git a/ui/src/main/java/org/akraino/validation/ui/data/SubmissionStatus.java b/ui/src/main/java/org/akraino/validation/ui/data/SubmissionStatus.java new file mode 100644 index 0000000..2e01d9b --- /dev/null +++ b/ui/src/main/java/org/akraino/validation/ui/data/SubmissionStatus.java @@ -0,0 +1,20 @@ +/* + * Copyright (c) 2019 AT&T Intellectual Property. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.akraino.validation.ui.data; + +public enum SubmissionStatus { + Submitted, Waiting, Running, Completed +} diff --git a/ui/src/main/java/org/akraino/validation/ui/entity/Blueprint.java b/ui/src/main/java/org/akraino/validation/ui/entity/Blueprint.java new file mode 100644 index 0000000..05a27cc --- /dev/null +++ b/ui/src/main/java/org/akraino/validation/ui/entity/Blueprint.java @@ -0,0 +1,62 @@ +/* + * Copyright (c) 2019 AT&T Intellectual Property. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. You may obtain + * a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + * implied. See the License for the specific language governing + * permissions and limitations under the License. + */ +package org.akraino.validation.ui.entity; + +import java.io.Serializable; + +import javax.persistence.Column; +import javax.persistence.Entity; +import javax.persistence.GeneratedValue; +import javax.persistence.GenerationType; +import javax.persistence.Id; +import javax.persistence.SequenceGenerator; +import javax.persistence.Table; + +@Entity +@Table(name = "akraino.blueprint") +public class Blueprint implements Serializable { + + /** + * + */ + private static final long serialVersionUID = 1L; + + @Id + @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "blueprint_id_generator") + @SequenceGenerator(name = "blueprint_id_generator", sequenceName = "akraino.seq_blueprint", allocationSize = 1) + @Column(name = "blueprint_id") + private int blueprintId; + + @Column(name = "blueprint_name") + private String blueprintName; + + public int getBlueprintId() { + return blueprintId; + } + + public void setBlueprintId(int blueprintId) { + this.blueprintId = blueprintId; + } + + public String getBlueprintName() { + return blueprintName; + } + + public void setBlueprintName(String blueprintName) { + this.blueprintName = blueprintName; + } + +} diff --git a/ui/src/main/java/org/akraino/validation/ui/entity/BlueprintInstance.java b/ui/src/main/java/org/akraino/validation/ui/entity/BlueprintInstance.java new file mode 100644 index 0000000..93206db --- /dev/null +++ b/ui/src/main/java/org/akraino/validation/ui/entity/BlueprintInstance.java @@ -0,0 +1,114 @@ +/* + * Copyright (c) 2019 AT&T Intellectual Property. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. You may obtain + * a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + * implied. See the License for the specific language governing + * permissions and limitations under the License. + */ +package org.akraino.validation.ui.entity; + +import java.io.Serializable; + +import javax.persistence.Column; +import javax.persistence.Entity; +import javax.persistence.GeneratedValue; +import javax.persistence.GenerationType; +import javax.persistence.Id; +import javax.persistence.JoinColumn; +import javax.persistence.ManyToOne; +import javax.persistence.OneToOne; +import javax.persistence.SequenceGenerator; +import javax.persistence.Table; + +import org.akraino.validation.ui.data.BlueprintLayer; + +@Entity +@Table(name = "akraino.blueprint_instance") +public class BlueprintInstance implements Serializable { + + /** + * + */ + private static final long serialVersionUID = 1L; + + @Id + @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "blueprint_instance_id_generator") + @SequenceGenerator(name = "blueprint_instance_id_generator", sequenceName = "akraino.seq_blueprint_instance", + allocationSize = 1) + @Column(name = "blueprint_instance_id") + private int blueprintInstId; + + @ManyToOne + @JoinColumn(name = "blueprint_id") + private Blueprint blueprint; + + @Column(name = "version") + private String version; + + @Column(name = "layer") + private BlueprintLayer layer; + + @Column(name = "layer_description") + private String layerDescription; + + @OneToOne + @JoinColumn(name = "timeslot_id") + private Timeslot timeslot; + + public int getBlueprintInstanceId() { + return blueprintInstId; + } + + public void setBlueprintInstanceId(int blueprintInstId) { + this.blueprintInstId = blueprintInstId; + } + + public Blueprint getBlueprint() { + return blueprint; + } + + public void setBlueprint(Blueprint blueprint) { + this.blueprint = blueprint; + } + + public void setVersion(String version) { + this.version = version; + } + + public String getVersion() { + return version; + } + + public BlueprintLayer getLayer() { + return layer; + } + + public void setLayer(BlueprintLayer layer) { + this.layer = layer; + } + + public void setLayerDescription(String layerDescription) { + this.layerDescription = layerDescription; + } + + public String getLayerDescription() { + return layerDescription; + } + + public void setTimeslot(Timeslot timeslot) { + this.timeslot = timeslot; + } + + public Timeslot getTimeslot() { + return this.timeslot; + } + +} diff --git a/ui/src/main/java/org/akraino/validation/ui/entity/Submission.java b/ui/src/main/java/org/akraino/validation/ui/entity/Submission.java new file mode 100644 index 0000000..1d5d157 --- /dev/null +++ b/ui/src/main/java/org/akraino/validation/ui/entity/Submission.java @@ -0,0 +1,98 @@ +/* + * Copyright (c) 2019 AT&T Intellectual Property. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. You may obtain + * a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + * implied. See the License for the specific language governing + * permissions and limitations under the License. + */ +package org.akraino.validation.ui.entity; + +import javax.persistence.Column; +import javax.persistence.Entity; +import javax.persistence.GeneratedValue; +import javax.persistence.GenerationType; +import javax.persistence.Id; +import javax.persistence.JoinColumn; +import javax.persistence.ManyToOne; +import javax.persistence.SequenceGenerator; +import javax.persistence.Table; + +import org.akraino.validation.ui.data.SubmissionStatus; + +@Entity +@Table(name = "akraino.submission") +public class Submission { + + /** + * + */ + private static final long serialVersionUID = 1L; + + @Id + @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "submission_id_generator") + @SequenceGenerator(name = "submission_id_generator", sequenceName = "akraino.seq_submission", allocationSize = 1) + @Column(name = "submission_id") + private int submissionId; + + @Column(name = "status") + private SubmissionStatus status; + + @Column(name = "jenkins_queue_job_item_url") + private String jnksJobUrl; + + @Column(name = "nexus_result_url") + private String nexusResultUrl; + + @ManyToOne + @JoinColumn(name = "blueprint_instance_id") + private BlueprintInstance blueprintInstance; + + public void setSubmissionId(int submissionId) { + this.submissionId = submissionId; + } + + public int getSubmissionId() { + return submissionId; + } + + public SubmissionStatus getSubmissionStatus() { + return this.status; + } + + public void setSubmissionStatus(SubmissionStatus submissionStatus) { + this.status = submissionStatus; + } + + public String getJenkinsQueueJobItemUrl() { + return this.jnksJobUrl; + } + + public void setJnksQueueJobItemUrl(String url) { + this.jnksJobUrl = url; + } + + public String getNexusResultUrl() { + return this.nexusResultUrl; + } + + public void setNexusResultUrl(String nexusResultUrl) { + this.nexusResultUrl = nexusResultUrl; + } + + public void setBlueprintInstance(BlueprintInstance blueprintInstance) { + this.blueprintInstance = blueprintInstance; + } + + public BlueprintInstance getBlueprintInstance() { + return this.blueprintInstance; + } + +} diff --git a/ui/src/main/java/org/akraino/validation/ui/entity/Timeslot.java b/ui/src/main/java/org/akraino/validation/ui/entity/Timeslot.java new file mode 100644 index 0000000..c53fa49 --- /dev/null +++ b/ui/src/main/java/org/akraino/validation/ui/entity/Timeslot.java @@ -0,0 +1,85 @@ +/* + * Copyright (c) 2019 AT&T Intellectual Property. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.akraino.validation.ui.entity; + +import java.io.Serializable; + +import javax.persistence.Column; +import javax.persistence.Entity; +import javax.persistence.GeneratedValue; +import javax.persistence.GenerationType; +import javax.persistence.Id; +import javax.persistence.SequenceGenerator; +import javax.persistence.Table; + +import org.akraino.validation.ui.data.Lab; + +@Entity +@Table(name = "akraino.timeslot") +public class Timeslot implements Serializable { + + /** + * + */ + private static final long serialVersionUID = 1L; + + @Id + @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "timeslot_id_generator") + @SequenceGenerator(name = "timeslot_id_generator", sequenceName = "akraino.seq_timeslot", allocationSize = 1) + @Column(name = "timeslot_id") + private int timeslotId; + + @Column(name = "start_date_time") + private String startDateTime; + + @Column(name = "duration") + private int duration; + + @Column(name = "lab") + private Lab lab; + + public void setTimeslotId(int timeslotId) { + this.timeslotId = timeslotId; + } + + public int getTimeslotId() { + return timeslotId; + } + + public void setStartDateTime(String startDateTime) { + this.startDateTime = startDateTime; + } + + public String getStartDateTime() { + return startDateTime; + } + + public void setDuration(int duration) { + this.duration = duration; + } + + public int getDuration() { + return duration; + } + + public void setLab(Lab lab) { + this.lab = lab; + } + + public Lab getLab() { + return lab; + } +} diff --git a/ui/src/main/java/org/akraino/validation/ui/service/BlueprintInstanceService.java b/ui/src/main/java/org/akraino/validation/ui/service/BlueprintInstanceService.java new file mode 100644 index 0000000..33914a4 --- /dev/null +++ b/ui/src/main/java/org/akraino/validation/ui/service/BlueprintInstanceService.java @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2019 AT&T Intellectual Property. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.akraino.validation.ui.service; + +import java.util.List; + +import org.akraino.validation.ui.dao.BlueprintInstanceDAO; +import org.akraino.validation.ui.entity.BlueprintInstance; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +@Service +@Transactional +public class BlueprintInstanceService { + + @Autowired + private BlueprintInstanceDAO blueprintInstDAO; + + public void saveBlueprintInstance(BlueprintInstance blueprintInstance) { + + blueprintInstDAO.saveOrUpdate(blueprintInstance); + + } + + public List getBlueprintInstances() { + + return blueprintInstDAO.getBlueprintInstances(); + + } + + public void deleteAll() { + blueprintInstDAO.deleteAll(); + } + +} diff --git a/ui/src/main/java/org/akraino/validation/ui/service/BlueprintService.java b/ui/src/main/java/org/akraino/validation/ui/service/BlueprintService.java new file mode 100644 index 0000000..019802c --- /dev/null +++ b/ui/src/main/java/org/akraino/validation/ui/service/BlueprintService.java @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2019 AT&T Intellectual Property. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.akraino.validation.ui.service; + +import java.util.List; + +import org.akraino.validation.ui.dao.BlueprintDAO; +import org.akraino.validation.ui.entity.Blueprint; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +@Service +@Transactional +public class BlueprintService { + + @Autowired + private BlueprintDAO blueprintDAO; + + public void saveBlueprint(Blueprint blueprint) { + + blueprintDAO.saveOrUpdate(blueprint); + + } + + public List getBlueprints() { + + return blueprintDAO.getBlueprints(); + + } + + public void deleteAll() { + blueprintDAO.deleteAll(); + } + +} diff --git a/ui/src/main/java/org/akraino/validation/ui/service/JenkinsJobNotificationService.java b/ui/src/main/java/org/akraino/validation/ui/service/JenkinsJobNotificationService.java new file mode 100644 index 0000000..0a50ad8 --- /dev/null +++ b/ui/src/main/java/org/akraino/validation/ui/service/JenkinsJobNotificationService.java @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2019 AT&T Intellectual Property. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. You may obtain + * a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + * implied. See the License for the specific language governing + * permissions and limitations under the License. + */ +package org.akraino.validation.ui.service; + +import org.akraino.validation.ui.data.JnksJobNotify; +import org.akraino.validation.ui.data.SubmissionStatus; +import org.akraino.validation.ui.entity.Submission; +import org.akraino.validation.ui.service.utils.SubmissionHelper; +import org.apache.log4j.Logger; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +@Service +@Transactional +public class JenkinsJobNotificationService { + + @Autowired + private SubmissionHelper submissionHelper; + + @Autowired + private SubmissionService submissionService; + + private static final Logger LOGGER = Logger.getLogger(JenkinsJobNotificationService.class); + + public void handle(JnksJobNotify jnksJobNotify) { + String jenkinsJobName = System.getenv("jenkins_job_name"); + if (!jenkinsJobName.equals(jnksJobNotify.getName())) { + return; + } + Submission submission = submissionService.getSubmission(Integer.toString(jnksJobNotify.getSubmissionId())); + if (submission == null) { + LOGGER.debug("No related submission was found."); + return; + } + submission.setNexusResultUrl(System.getenv("nexus_results_url") + "/" + + submission.getBlueprintInstance().getTimeslot().getLab().name().toLowerCase() + "-blu-val" + + "/job/validation/" + String.valueOf(jnksJobNotify.getbuildNumber())); + LOGGER.info("Updating submission with id: " + submission.getSubmissionId()); + submission.setSubmissionStatus(SubmissionStatus.Completed); + submissionHelper.saveSubmission(submission); + } + +} diff --git a/ui/src/main/java/org/akraino/validation/ui/service/ResultService.java b/ui/src/main/java/org/akraino/validation/ui/service/ResultService.java new file mode 100644 index 0000000..1deffa0 --- /dev/null +++ b/ui/src/main/java/org/akraino/validation/ui/service/ResultService.java @@ -0,0 +1,84 @@ +/* + * Copyright (c) 2019 AT&T Intellectual Property. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. You may obtain + * a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + * implied. See the License for the specific language governing + * permissions and limitations under the License. + */ +package org.akraino.validation.ui.service; + +import java.io.IOException; +import java.net.MalformedURLException; +import java.net.URL; +import java.security.KeyManagementException; +import java.security.NoSuchAlgorithmException; +import java.util.List; + +import org.akraino.validation.ui.client.jenkins.JenkinsExecutorClient; +import org.akraino.validation.ui.client.jenkins.resources.QueueJobItem; +import org.akraino.validation.ui.client.jenkins.resources.QueueJobItem.Executable; +import org.akraino.validation.ui.client.nexus.NexusExecutorClient; +import org.akraino.validation.ui.client.nexus.resources.RobotTestResult; +import org.akraino.validation.ui.entity.Submission; +import org.apache.commons.httpclient.HttpException; +import org.apache.log4j.Logger; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import com.fasterxml.jackson.core.JsonParseException; +import com.fasterxml.jackson.databind.JsonMappingException; +import com.sun.jersey.api.client.ClientHandlerException; +import com.sun.jersey.api.client.UniformInterfaceException; + +@Service +public class ResultService { + + private static final Logger LOGGER = Logger.getLogger(ResultService.class); + + @Autowired + private SubmissionService submissionService; + + @Deprecated + public URL getNexusResultUrl(Submission submission) + throws MalformedURLException, KeyManagementException, HttpException, ClientHandlerException, + UniformInterfaceException, NoSuchAlgorithmException, InterruptedException { + + String url = System.getenv("jenkins_url"); + String userName = System.getenv("jenkins_user_name"); + String password = System.getenv("jenkins_user_pwd"); + + Executable executable = null; + while (executable == null) { + JenkinsExecutorClient client; + client = JenkinsExecutorClient.getInstance(userName, password, url); + QueueJobItem queueJobItem = client.getQueueJobItem(new URL(submission.getJenkinsQueueJobItemUrl())); + executable = queueJobItem.getExecutable(); + Thread.sleep(2000); + } + return new URL(System.getenv("nexus_results_url") + "/" + + submission.getBlueprintInstance().getTimeslot().getLab().name().toLowerCase() + "-blu-val" + + "/job/validation/" + String.valueOf(executable.getNumber())); + } + + public List getRobotTestResults(String submissionId) + throws JsonParseException, JsonMappingException, KeyManagementException, ClientHandlerException, + UniformInterfaceException, NoSuchAlgorithmException, IOException { + Submission submission = submissionService.getSubmission(submissionId); + if (submission == null) { + LOGGER.info("Requested submission does not exist"); + return null; + } + String nexusUrl = submission.getNexusResultUrl(); + NexusExecutorClient client = new NexusExecutorClient(nexusUrl + "/results"); + return client.getRobotTestResults(); + } + +} diff --git a/ui/src/main/java/org/akraino/validation/ui/service/SubmissionService.java b/ui/src/main/java/org/akraino/validation/ui/service/SubmissionService.java new file mode 100644 index 0000000..a6b1fca --- /dev/null +++ b/ui/src/main/java/org/akraino/validation/ui/service/SubmissionService.java @@ -0,0 +1,151 @@ +/* + * Copyright (c) 2019 AT&T Intellectual Property. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. You may obtain + * a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + * implied. See the License for the specific language governing + * permissions and limitations under the License. + */ +package org.akraino.validation.ui.service; + +import java.net.DatagramSocket; +import java.net.InetAddress; +import java.net.MalformedURLException; +import java.net.SocketException; +import java.net.UnknownHostException; +import java.security.KeyManagementException; +import java.security.NoSuchAlgorithmException; +import java.util.ArrayList; +import java.util.List; +import java.util.Random; +import java.util.concurrent.CompletableFuture; + +import org.akraino.validation.ui.client.jenkins.JenkinsExecutorClient; +import org.akraino.validation.ui.client.jenkins.resources.Parameter; +import org.akraino.validation.ui.client.jenkins.resources.Parameters; +import org.akraino.validation.ui.config.AppInitializer; +import org.akraino.validation.ui.dao.SubmissionDAO; +import org.akraino.validation.ui.data.SubmissionStatus; +import org.akraino.validation.ui.entity.Submission; +import org.akraino.validation.ui.service.utils.PrioritySupplier; +import org.akraino.validation.ui.service.utils.SubmissionHelper; +import org.apache.commons.httpclient.HttpException; +import org.apache.log4j.Logger; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import com.sun.jersey.api.client.ClientHandlerException; +import com.sun.jersey.api.client.UniformInterfaceException; + +@Service +@Transactional +public class SubmissionService { + + private static final Logger LOGGER = Logger.getLogger(SubmissionService.class); + + @Autowired + private SubmissionDAO submissionDAO; + + @Autowired + private SubmissionHelper submissionHelper; + + public Submission saveSubmission(Submission submission) { + submission.setSubmissionStatus(SubmissionStatus.Submitted); + submissionDAO.saveOrUpdate(submission); + + JenkinsTriggerSubmissionJob task = new JenkinsTriggerSubmissionJob(submission); + CompletableFuture completableFuture = + CompletableFuture.supplyAsync(new PrioritySupplier<>(1, task::execute), AppInitializer.executorService); + completableFuture.thenAcceptAsync(result -> this.callbackNotify(result)); + + return submission; + } + + public List getSubmissions() { + return submissionDAO.getSubmissions(); + } + + public Submission getSubmission(String submissionId) { + return submissionDAO.getSubmission(Integer.valueOf(submissionId)); + } + + public void deleteSubmission(Integer submissionId) { + submissionDAO.deleteSubmission(submissionId); + } + + public void deleteAll() { + submissionDAO.deleteAll(); + } + + private void callbackNotify(Submission submission) { + if (submission == null) { + return; + } + submission.setSubmissionStatus(SubmissionStatus.Running); + submissionHelper.saveSubmission(submission); + } + + private class JenkinsTriggerSubmissionJob { + + private Submission submission; + + public JenkinsTriggerSubmissionJob(Submission submission) { + this.submission = submission; + } + + public Submission execute() { + String url = System.getenv("jenkins_url"); + String userName = System.getenv("jenkins_user_name"); + String userPassword = System.getenv("jenkins_user_pwd"); + String jobName = System.getenv("jenkins_job_name"); + List listOfParameters = new ArrayList(); + Parameters parameters = new Parameters(); + Parameter parameter = new Parameter(); + parameter.setName("SUBMISSION_ID"); + parameter.setValue(String.valueOf(submission.getSubmissionId())); + listOfParameters.add(parameter); + parameter = new Parameter(); + parameter.setName("BLUEPRINT"); + parameter.setValue(submission.getBlueprintInstance().getBlueprint().getBlueprintName()); + listOfParameters.add(parameter); + parameter = new Parameter(); + parameter.setName("LAYER"); + parameter.setValue(submission.getBlueprintInstance().getLayer().name()); + listOfParameters.add(parameter); + parameter = new Parameter(); + parameter.setName("UI_IP"); + Random random = new Random(); + String localIP = null; + try (final DatagramSocket socket = new DatagramSocket()) { + socket.connect(InetAddress.getByName(random.nextInt(256) + "." + random.nextInt(256) + "." + + random.nextInt(256) + "." + random.nextInt(256)), 10002); + localIP = socket.getLocalAddress().getHostAddress(); + } catch (SocketException | UnknownHostException e1) { + LOGGER.error(e1); + return null; + } + parameter.setValue(localIP); + listOfParameters.add(parameter); + parameters.setParameter(listOfParameters); + JenkinsExecutorClient client; + try { + client = JenkinsExecutorClient.getInstance(userName, userPassword, url); + submission.setJnksQueueJobItemUrl(client.postJobWithQueryParams(jobName, parameters).toString()); + } catch (MalformedURLException | KeyManagementException | HttpException | ClientHandlerException + | UniformInterfaceException | NoSuchAlgorithmException e) { + LOGGER.error(e); + return null; + } + return submission; + } + } + +} diff --git a/ui/src/main/java/org/akraino/validation/ui/service/TimeslotService.java b/ui/src/main/java/org/akraino/validation/ui/service/TimeslotService.java new file mode 100644 index 0000000..421c2b6 --- /dev/null +++ b/ui/src/main/java/org/akraino/validation/ui/service/TimeslotService.java @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2019 AT&T Intellectual Property. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.akraino.validation.ui.service; + +import java.util.List; + +import org.akraino.validation.ui.dao.TimeslotDAO; +import org.akraino.validation.ui.entity.Timeslot; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +@Service +@Transactional +public class TimeslotService { + + @Autowired + private TimeslotDAO timeslotDAO; + + public void saveTimeslot(Timeslot timeslot) { + + timeslotDAO.saveOrUpdate(timeslot); + + } + + public List getTimeslots() { + + return timeslotDAO.getTimeslots(); + + } + + public void deleteAll() { + timeslotDAO.deleteAll(); + } + +} diff --git a/ui/src/main/java/org/akraino/validation/ui/service/utils/PrioritySupplier.java b/ui/src/main/java/org/akraino/validation/ui/service/utils/PrioritySupplier.java new file mode 100644 index 0000000..e1c53d5 --- /dev/null +++ b/ui/src/main/java/org/akraino/validation/ui/service/utils/PrioritySupplier.java @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2019 AT&T Intellectual Property. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.akraino.validation.ui.service.utils; + +import java.util.function.Supplier; + +public class PrioritySupplier implements Supplier, WithPriority { + private final int priorityField; + private final Supplier supplier; + + public PrioritySupplier(int priorityField, Supplier supplier) { + this.priorityField = priorityField; + this.supplier = supplier; + } + + @Override + public T get() { + return supplier.get(); + } + + @Override + public int priority() { + return priorityField; + } +} diff --git a/ui/src/main/java/org/akraino/validation/ui/service/utils/SubmissionHelper.java b/ui/src/main/java/org/akraino/validation/ui/service/utils/SubmissionHelper.java new file mode 100644 index 0000000..7a36b23 --- /dev/null +++ b/ui/src/main/java/org/akraino/validation/ui/service/utils/SubmissionHelper.java @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2019 AT&T Intellectual Property. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.akraino.validation.ui.service.utils; + +import org.akraino.validation.ui.dao.SubmissionDAO; +import org.akraino.validation.ui.entity.Submission; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +@Service +@Transactional +public class SubmissionHelper { + + @Autowired + private SubmissionDAO submissionDAO; + + public Submission saveSubmission(Submission submission) { + submissionDAO.saveOrUpdate(submission); + return submission; + } + +} diff --git a/ui/src/main/java/org/akraino/validation/ui/service/utils/WithPriority.java b/ui/src/main/java/org/akraino/validation/ui/service/utils/WithPriority.java new file mode 100644 index 0000000..25ea9f6 --- /dev/null +++ b/ui/src/main/java/org/akraino/validation/ui/service/utils/WithPriority.java @@ -0,0 +1,26 @@ +/* + * Copyright (c) 2019 AT&T Intellectual Property. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.akraino.validation.ui.service.utils; + +public interface WithPriority extends Comparable { + int priority(); + + @Override + default int compareTo(WithPriority withPriority) { + // Reverse comparison so higher priority comes first. + return Integer.compare(withPriority.priority(), priority()); + } +} diff --git a/ui/src/main/resources/app.properties b/ui/src/main/resources/app.properties new file mode 100644 index 0000000..76281ca --- /dev/null +++ b/ui/src/main/resources/app.properties @@ -0,0 +1,21 @@ +# Copyright (c) 2019 AT&T Intellectual Property. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +#LDAP details for authentication & authorization +apacheds.ldap.url = ldap://localhost:10389/dc=akraino,dc=org + +#DB connection properties +postgres.db.url = jdbc:postgresql://localhost:6432/admin +postgres.db.user.name = admin + diff --git a/ui/src/main/resources/hibernate.properties b/ui/src/main/resources/hibernate.properties new file mode 100644 index 0000000..a66c68f --- /dev/null +++ b/ui/src/main/resources/hibernate.properties @@ -0,0 +1,21 @@ +# Copyright (c) 2019 AT&T Intellectual Property. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +hibernate.dialect = org.hibernate.dialect.PostgreSQLDialect +hibernate.show_sql = true +hibernate.c3p0.min_size = 5 +hibernate.c3p0.max_size = 20 +hibernate.c3p0.acquire_increment = 2 +hibernate.c3p0.max_statements = 150 +hibernate.jdbc.use_streams_for_binary = true \ No newline at end of file diff --git a/ui/src/main/resources/log4j.properties b/ui/src/main/resources/log4j.properties new file mode 100644 index 0000000..4484b3f --- /dev/null +++ b/ui/src/main/resources/log4j.properties @@ -0,0 +1,34 @@ +# Copyright (c) 2019 AT&T Intellectual Property. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Direct log messages to a log file +log4j.rootLogger=INFO, stdout, file +log4j.logger.org.hibernate.SQL=TRACE, stdout + +# Redirect log messages to console +log4j.appender.stdout=org.apache.log4j.ConsoleAppender +log4j.appender.stdout.Threshold=WARN +log4j.appender.stdout.Target=System.out +log4j.appender.stdout.layout=org.apache.log4j.PatternLayout +log4j.appender.stdout.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss} %-5p %c{1}:%L - %m%n + +# Redirect log messages to a log file, support file rolling. +log4j.appender.file=org.apache.log4j.RollingFileAppender +log4j.appender.stdout.Threshold=DEBUG +#log4j.appender.file.File=C:\\Users\\ld261v\\Downloads\\ak1.log +log4j.appender.file.File=/usr/local/tomcat/logs/akraino.log +log4j.appender.file.MaxFileSize=5MB +log4j.appender.file.MaxBackupIndex=10 +log4j.appender.file.layout=org.apache.log4j.PatternLayout +log4j.appender.file.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss} %-5p %c{1}:%L - %m%n \ No newline at end of file diff --git a/ui/src/main/webapp/.eslintrc b/ui/src/main/webapp/.eslintrc new file mode 100644 index 0000000..53fe50e --- /dev/null +++ b/ui/src/main/webapp/.eslintrc @@ -0,0 +1,9 @@ +{ + "globals": { + "angular": 1, + "console": 1, + "confirm":1, + "localStorage":1, + "window":1 + } +} \ No newline at end of file diff --git a/ui/src/main/webapp/WEB-INF/views/welcome.jsp b/ui/src/main/webapp/WEB-INF/views/welcome.jsp new file mode 100755 index 0000000..0f3d695 --- /dev/null +++ b/ui/src/main/webapp/WEB-INF/views/welcome.jsp @@ -0,0 +1,28 @@ + +<%@taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%> + + + + Spring 4 MVC Hello World Example with Maven Eclipse + + + +

Hello World, Spring MVC

+ +

Welcome, ${name}

+ + \ No newline at end of file diff --git a/ui/src/main/webapp/WEB-INF/web.xml b/ui/src/main/webapp/WEB-INF/web.xml new file mode 100755 index 0000000..0ef6de8 --- /dev/null +++ b/ui/src/main/webapp/WEB-INF/web.xml @@ -0,0 +1,25 @@ + + + + + + Archetype Created Web Application + + + diff --git a/ui/src/main/webapp/index.html b/ui/src/main/webapp/index.html new file mode 100755 index 0000000..cb23409 --- /dev/null +++ b/ui/src/main/webapp/index.html @@ -0,0 +1,115 @@ + + + + + + +AKRAINO Blueprint Validation UI + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + \ No newline at end of file diff --git a/ui/src/main/webapp/resources/css/ngDialog-theme-default.css b/ui/src/main/webapp/resources/css/ngDialog-theme-default.css new file mode 100644 index 0000000..5845704 --- /dev/null +++ b/ui/src/main/webapp/resources/css/ngDialog-theme-default.css @@ -0,0 +1,211 @@ +/* + * Copyright (c) 2019 AT&T Intellectual Property. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +@-webkit-keyframes ngdialog-flyin { + 0% { + opacity: 0; + -webkit-transform: translateY(-40px); + transform: translateY(-40px); + } + + 100% { + opacity: 1; + -webkit-transform: translateY(0); + transform: translateY(0); + } +} + +@keyframes ngdialog-flyin { + 0% { + opacity: 0; + -webkit-transform: translateY(-40px); + -ms-transform: translateY(-40px); + transform: translateY(-40px); + } + + 100% { + opacity: 1; + -webkit-transform: translateY(0); + -ms-transform: translateY(0); + transform: translateY(0); + } +} + +@-webkit-keyframes ngdialog-flyout { + 0% { + opacity: 1; + -webkit-transform: translateY(0); + transform: translateY(0); + } + + 100% { + opacity: 0; + -webkit-transform: translateY(-40px); + transform: translateY(-40px); + } +} + +@keyframes ngdialog-flyout { + 0% { + opacity: 1; + -webkit-transform: translateY(0); + -ms-transform: translateY(0); + transform: translateY(0); + } + + 100% { + opacity: 0; + -webkit-transform: translateY(-40px); + -ms-transform: translateY(-40px); + transform: translateY(-40px); + } +} + +.ngdialog.ngdialog-theme-default { + padding-bottom: 160px; + padding-top: 160px; +} + +.ngdialog.ngdialog-theme-default.ngdialog-closing .ngdialog-content { + -webkit-animation: ngdialog-flyout .5s; + animation: ngdialog-flyout .5s; +} + +.ngdialog.ngdialog-theme-default .ngdialog-content { + -webkit-animation: ngdialog-flyin .5s; + animation: ngdialog-flyin .5s; + background: #F9F4E5; + border-radius: 5px; + color: #444; + font-family: 'Helvetica',sans-serif; + font-size: 1.1em; + line-height: 1.5em; + margin: 0 auto; + max-width: 100%; + padding: 1em; + position: relative; + width: 450px; +} + +.ngdialog.ngdialog-theme-default .ngdialog-close { + border-radius: 5px; + cursor: pointer; + position: absolute; + right: 0; + top: 0; +} + +.ngdialog.ngdialog-theme-default .ngdialog-close:before { + background: transparent; + border-radius: 3px; + color: #bbb; + content: '\00D7'; + font-size: 26px; + font-weight: 400; + height: 30px; + line-height: 26px; + position: absolute; + right: 3px; + text-align: center; + top: 3px; + width: 30px; +} + +.ngdialog.ngdialog-theme-default .ngdialog-close:hover:before, +.ngdialog.ngdialog-theme-default .ngdialog-close:active:before { + color: #777; +} + +.ngdialog.ngdialog-theme-default .ngdialog-message { + margin-bottom: .5em; +} + +.ngdialog.ngdialog-theme-default .ngdialog-input { + margin-bottom: 1em; +} + +.ngdialog.ngdialog-theme-default .ngdialog-input textarea, +.ngdialog.ngdialog-theme-default .ngdialog-input input[type="text"], +.ngdialog.ngdialog-theme-default .ngdialog-input input[type="password"], +.ngdialog.ngdialog-theme-default .ngdialog-input input[type="email"], +.ngdialog.ngdialog-theme-default .ngdialog-input input[type="url"] { + background: #fff; + border: 0; + border-radius: 3px; + font-family: inherit; + font-size: inherit; + font-weight: inherit; + margin: 0 0 .25em; + min-height: 2.5em; + padding: .25em .67em; + width: 100%; +} + +.ngdialog.ngdialog-theme-default .ngdialog-input textarea:focus, +.ngdialog.ngdialog-theme-default .ngdialog-input input[type="text"]:focus, +.ngdialog.ngdialog-theme-default .ngdialog-input input[type="password"]:focus, +.ngdialog.ngdialog-theme-default .ngdialog-input input[type="email"]:focus, +.ngdialog.ngdialog-theme-default .ngdialog-input input[type="url"]:focus { + -webkit-box-shadow: inset 0 0 0 2px #8dbdf1; + box-shadow: inset 0 0 0 2px #8dbdf1; + outline: none; +} + +.ngdialog.ngdialog-theme-default .ngdialog-buttons { + *zoom: 1; +} + +.ngdialog.ngdialog-theme-default .ngdialog-buttons:after { + content: ''; + display: table; + clear: both; +} + +.ngdialog.ngdialog-theme-default .ngdialog-button { + border: 0; + border-radius: 3px; + cursor: pointer; + float: right; + font-family: inherit; + font-size: .8em; + letter-spacing: .1em; + line-height: 1em; + margin: 0 0 0 .5em; + padding: .75em 2em; + text-transform: uppercase; +} + +.ngdialog.ngdialog-theme-default .ngdialog-button:focus { + -webkit-animation: ngdialog-pulse 1.1s infinite; + animation: ngdialog-pulse 1.1s infinite; + outline: none; +} + +@media (max-width: 568px) { + .ngdialog.ngdialog-theme-default .ngdialog-button:focus { + -webkit-animation: none; + animation: none; + } +} + +.ngdialog.ngdialog-theme-default .ngdialog-button.ngdialog-button-primary { + background: #3288e6; + color: #fff; +} + +.ngdialog.ngdialog-theme-default .ngdialog-button.ngdialog-button-secondary { + background: #e0e0e0; + color: #777; +} \ No newline at end of file diff --git a/ui/src/main/webapp/resources/css/style.css b/ui/src/main/webapp/resources/css/style.css new file mode 100755 index 0000000..7680da0 --- /dev/null +++ b/ui/src/main/webapp/resources/css/style.css @@ -0,0 +1,611 @@ +/* + * Copyright (c) 2019 AT&T Intellectual Property. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +.img-arredondadaSide { + border-radius: 100%; + w overflow: hidden; + height: 100px; + width:100px; + background:#6495ED; + margin-top:10px; + margin-left: 5px; +} + .img-arredondadaChat { + border-radius: 100%; + overflow: hidden; + height: 50px; + width:50px; + background: black; +} + .tema{ + color:red; +} + .chat-container { + width: 400px; + height: 100%; + margin: 0 auto; +} + .corStatusFinalizado{ + color:green; +} + .corNormal{ + color:#3366FF; +} + .corStatusNaoFinalizado{ + color:red; +} + .alinharCentro{ + text-align: center; +} + .user-panel { + padding: 10px; +} + .user-panel:before, .user-panel:after { + display: table; + content: " "; +} + .user-panel:after { + clear: both; +} + .user-panel > .image > img { + width: 45px; + height: 45px; +} + .user-panel > .info { + font-weight: 600; + padding: 5px 5px 5px 15px; + font-size: 14px; + line-height: 1; +} + .user-panel > .info > p { + margin-bottom: 9px; +} + .user-panel > .info > a { + text-decoration: none; + padding-right: 5px; + margin-top: 3px; + font-size: 11px; + font-weight: normal; +} + .user-panel > .info > a > .fa, .user-panel > .info > a > .ion, .user-panel > .info > a > .glyphicon { + margin-right: 3px; +} + #wrapper { + padding-left: 0; + -webkit-transition: all 0.5s ease; + -moz-transition: all 0.5s ease; + -o-transition: all 0.5s ease; + transition: all 0.5s ease; + margin-top: -20px; +} + #wrapper.toggled { + padding-left: 250px; +} + #sidebar-wrapper { + z-index: 1000; + position: absolute; + left: 250px; + width: 0; + height:100vh; + margin-left: -250px; + overflow-y: auto; + background: #cccccc; + -webkit-transition: all 0.5s ease; + -moz-transition: all 0.5s ease; + -o-transition: all 0.5s ease; + transition: all 0.5s ease; +} + #wrapper.toggled #sidebar-wrapper { + width: 250px; +} + #page-content-wrapper { + width: 100%; +} + #wrapper.toggled #page-content-wrapper { + position: absolute; + margin-right: -250px; +} +/* Sidebar Styles */ + .sidebar-nav { + position: absolute; + top: 0; + width: 250px; + margin: 0; + padding: 0; + list-style: none; +} + .sidebar-nav li { + text-indent: 20px; + line-height: 40px; + margin-left: -25px; + color: #000000; +} + .logo{ + color: rgb(105, 183, 105); + font-size: 36px; + font-weight: 700; + line-height: 39.6px; + margin-left:20px; + margin-top:10px +} + .fa { + display: inline-block; + font-family: FontAwesome; + font-style: normal; + font-weight: normal; + line-height: 1; + font-size-adjust: none; + font-stretch: normal; + font-feature-settings: normal; + font-language-override: normal; + font-kerning: auto; + font-synthesis: weight style; + font-variant: normal; + font-size: inherit; + text-rendering: auto; + padding-right: 10px; +} + .containerLogin{ + padding-right: 15px; + padding-left: 15px; + margin-right: auto; + margin-top: 100px; + margin-left: auto; + width: 30%; +} + .sidebar-nav li a { + display: block; + text-decoration: none; + color: #000000; +} + + .sidebar-nav li a:hover { + text-decoration: none; + color: #fff; + background: rgba(255,255,255,0.2); +} + + .sidebar-nav li a.example{ + text-decoration: none; + color: #fff; + background: #999999; +} +sidebar-nav > .sidebar-brand { + height: 65px; + font-size: 18px; + line-height: 60px; +} + .sidebar-nav > .sidebar-brand a { + color: #999999; +} + .sidebar-nav > .sidebar-brand a:hover { + color: #fff; + background: none; +} + .sidebar-nav > .sidebar-brand a:active { + color: #fff; + background: none; +} + @media only screen and (max-height: 650px) and (min-width:768px){ + #sidebar-wrapper { + width: 250px; + position: absolute; + height:200%; + } +} + @media only screen and (max-height: 450px) and (min-width:768px){ + #sidebar-wrapper { + width: 250px; + position: absolute; + height:160%; + } +} + @media only screen and (max-height: 1200px) and (min-width:1366px){ + #sidebar-wrapper { + width: 250px; + position: absolute; + height:100%; + } +} + @media(min-width:768px) { + #wrapper { + padding-left: 120px; + } + #wrapper.toggled { + padding-left: 0; + } + #sidebar-wrapper { + width: 250px; + } + #wrapper.toggled #sidebar-wrapper { + width: 0; + } + #page-content-wrapper { + position: relative; + } + #wrapper.toggled #page-content-wrapper { + position: relative; + margin-right: 0; + } +} + + * { + box-sizing: border-box; +} + body { + margin: 0; + padding:0; + + font-family: Arial; + height:calc(100% - 70px); + height:-moz-calc(100% - 70px); + height:-webkit-calc(100% - 70px); + +} +html{margin:0;padding:0;} + + .header { + overflow: hidden; + background-color: #000000; + padding: 8px 10px; +} + .header a { + float: left; + color: white; + text-align: center; + padding: 12px; + text-decoration: none; + font-size: 18px; + line-height: 25px; + border-radius: 4px; +} + .header a.logo { + font-size: 25px; + font-weight: bold; +} + .header-right { + float: right; +} + .akrbutton { + background-color: #4d4d4d; + border: none; + color: white; + padding: 8px 15px; + text-align: center; + text-decoration: none; + display: inline-block; + font-size: 12px; + margin: 3% 2%; + cursor: pointer; + border-radius: 5px; +} + .refreshbutton { + background-color: #4d4d4d; + border: none; + color: white; + padding: 7px 14px; + text-align: center; + text-decoration: none; + display: inline-block; + cursor: pointer; + border-radius: 5px; + +} + .akrtheader { + padding-top: 12px; + padding-bottom: 12px; + text-align: left; + background-color: #4CAF50 +} + table, td { + border: 1px solid #ddd; +} + table { + border-collapse: collapse; + width: 100%;} + + .siteStatusTable th { + padding: 5px; + text-align: left; + background-color: #cccccc; + border: 1px solid #ddd; +} + .siteStatusTable td { + padding-top: 5px; + padding-bottom:5px; +} +.nodeTable th { + padding: 10px; + text-align: left; + background-color: #cccccc; + border: 0px solid #ddd; +} + .nodeTable td { + padding-top: 5px; + padding-bottom:5px; +} + .siteaddOnsTable th { + padding: 10px; + text-align: left; + background-color: #cccccc; + border: 1px solid #ddd; +} + .siteaddOnsTable td { + padding-top: 5px; + padding-bottom:5px; +} + + + .sitetempestsTable th { + padding: 10px; + text-align: left; + background-color: #cccccc; + border: 1px solid #ddd; +} + .sitetempestsTable td { + padding-top: 5px; + padding-bottom:5px; +} + + +.shardwareTable th { + padding: 5px; + text-align: left; + background-color: #cccccc; + border: 1px solid #ddd; +} + .shardwareTable td { + padding-top: 3px; + padding-bottom:3px; +} +.rackTable th { + padding: 10px; + text-align: left; + background-color: #cccccc; + border: 1px solid #ddd; +} + .rackTable td { + padding-top: 5px; + padding-bottom:5px; +} + +.sitebuildTable th { + padding: 10px; + text-align: left; + background-color: #cccccc; + border: 1px solid #ddd; +} + .sitebuildTable td { + padding-top: 5px; + padding-bottom:5px; +} + + .softwareTable th { + padding: 10px; + text-align: left; + background-color: #cccccc; + border: 1px solid #ddd; +} + .softwareTable td { + padding-top: 5px; + padding-bottom:5px; +} +.popUpTable th { + padding: 10px; + text-align: left; + background-color: #cccccc; + border: 1px solid #ddd; +} + .popUpTable td { + padding-top: 5px; + padding-bottom:5px; +} +/*.pagination { + display: inline-block; + float:right; +} + .pagination li { + list-style-type:none; + color: white; + float: left; + padding: 8px 16px; + text-decoration: none; + transition: background-color .3s; + border: 1px solid #ddd; +} + .pagination li.active { + background-color: #DCDCDC; + color: white; + border: 1px solid #ddd; +}*/ + button:disabled { + background: #dddddd; +} + .select-style { + border: 1px solid #ccc; + width: 240px; + height: 40px; + border-radius: 3px; + overflow: hidden; + background-position: right; +} + .select-style select { + + width: 100%; + border: 0px; + box-shadow: none; + background:none; + background-image: none; + -webkit-appearance: none; + outline: 0px; + +} +.selectStyle select option{ + height:30px; + padding-top:5px; +} +@-moz-document url-prefix() { + select.example { + padding-right: 25px; + + height:40px; + + background-image: url("data:image/svg+xml,\ + \ + \ + "); + background-repeat: no-repeat; + background-position: calc(100% - 7px) 50%; + -moz-appearance: none; + appearance: none; + + } +} +@-moz-document url-prefix() { + select.exampleTable { + + + height:25px; + + background-image: url("data:image/svg+xml,\ + \ + \ + "); + background-repeat: no-repeat; + background-position: calc(100% - 7px) 50%; + -moz-appearance: none; + appearance: none; + + } +} + .select-style select:focus { + outline: none; +} + .child_div_1{ + float:left; + margin-right:50px; +} + .child_div_2{ + float:right; + margin-right:50%; +} + .ngdialog { + margin-top:-100px; + padding-top:10px; + overflow-y: auto; +} + .addOnForm input[type=text], select, textarea { + width: 40%; + padding: 3px; + border: 0.5px solid #ccc; + border-radius: 4px; + box-sizing: border-box; + margin-top: 3px; + margin-bottom: 3px; + resize: vertical; +} + .tempestclassForm input[type=text], select, textarea { + width: 40%; + padding: 3px; + border: 0.5px solid #ccc; + border-radius: 4px; + box-sizing: border-box; + margin-top: 3px; + margin-bottom: 3px; + resize: vertical; +} +.hardwareForm input[type=text], select, textarea { + width: 40%; + padding: 3px; + border: 0.5px solid #ccc; + border-radius: 4px; + box-sizing: border-box; + margin-top: 3px; + margin-bottom: 3px; + resize: vertical; +} +.podForm input[type=text], select, textarea { + width: 40%; + padding: 3px; + border: 0.5px solid #ccc; + border-radius: 4px; + box-sizing: border-box; + margin-top: 3px; + margin-bottom: 3px; + resize: vertical; +} +.uploadForm input[type=text], select, textarea { + width: 40%; + padding: 3px; + border: 0.5px solid #ccc; + border-radius: 4px; + box-sizing: border-box; + margin-top: 3px; + margin-bottom: 3px; + resize: vertical; +} +.vnfForm input[type=text], select, textarea { + width: 40%; + padding: 3px; + border: 0.5px solid #ccc; + border-radius: 4px; + box-sizing: border-box; + margin-top: 3px; + margin-bottom: 3px; + resize: vertical; +} +.siteForm input[type=text], select, textarea { + width: 40%; + padding: 3px; + border: 0.5px solid #ccc; + border-radius: 4px; + box-sizing: border-box; + margin-top: 3px; + margin-bottom: 3px; + resize: vertical; +} +.siteForm li input[type=text], select, textarea { + width: 40%; + padding: 3px; + border: 0.5px solid #ccc; + border-radius: 4px; + box-sizing: border-box; + margin-top: 3px; + margin-bottom: 3px; + resize: vertical; +} + + label { + font-weight: normal !important; +} +.ngdialog-custom{ + background: #e6e6e6; +} +#footerlogo{ + position:absolute; + display:inline-block; + bottom:0; + width: 250px; +} +.borderFrame{ + margin-top:2px; + border:2px solid #cdcdcd; + /*border-radius: 0.1px; + /*-moz-border-radius: 0.1px; + -webkit-border-radius:0.1px;*/ +} diff --git a/ui/src/main/webapp/resources/images/logo_akraino_edge_stack.png b/ui/src/main/webapp/resources/images/logo_akraino_edge_stack.png new file mode 100755 index 0000000..c81bb53 Binary files /dev/null and b/ui/src/main/webapp/resources/images/logo_akraino_edge_stack.png differ diff --git a/ui/src/main/webapp/resources/js/AECCommittedSubmissionsController.js b/ui/src/main/webapp/resources/js/AECCommittedSubmissionsController.js new file mode 100644 index 0000000..9690793 --- /dev/null +++ b/ui/src/main/webapp/resources/js/AECCommittedSubmissionsController.js @@ -0,0 +1,61 @@ +/* + * Copyright (c) 2019 AT&T Intellectual Property. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +var AECBlueprintValidationUIApp = angular + .module('BlueprintValidationUIManagement'); + +AECBlueprintValidationUIApp.controller('AECCommittedSubmissionsController', + function($scope, restAPISvc, $interval, refreshPeriod) { + + $scope.submissionIdList = []; + + restAPISvc.getRestAPI("/api/submission/", function(data) { + $scope.submissions = data; + }); + + $scope.refreshCommittedSubmissions = function() { + restAPISvc.getRestAPI("/api/submission/", function(data) { + $scope.submissions = data; + }); + } + + $scope.modifySubmissionIdList = function(id) { + if ($scope.submissionIdList.indexOf(id) === -1) { + $scope.submissionIdList.push(id); + } else { + $scope.submissionIdList.splice($scope.submissionIdList + .indexOf(id), 1); + } + } + + $scope.deleteSubmissions = function() { + var confirmation = confirm("Are you sure?"); + if (confirmation == true) { + angular.forEach($scope.submissionIdList, function(id) { + var submission = { + "submissionId" : id + }; + restAPISvc + .deleteRestAPI("/api/submission/", submission); + }); + } + } + + $interval(function() { + $scope.refreshCommittedSubmissions(); + }, refreshPeriod); + + }); diff --git a/ui/src/main/webapp/resources/js/AECFindBySubmissionIdController.js b/ui/src/main/webapp/resources/js/AECFindBySubmissionIdController.js new file mode 100644 index 0000000..2d1a99c --- /dev/null +++ b/ui/src/main/webapp/resources/js/AECFindBySubmissionIdController.js @@ -0,0 +1,72 @@ +/* + * Copyright (c) 2019 AT&T Intellectual Property. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +var AECBlueprintValidationUIApp = angular + .module('BlueprintValidationUIManagement'); + +AECBlueprintValidationUIApp + .controller( + 'AECFindBySubmissionIdController', + function($scope, restAPISvc) { + + initialize(); + + function initialize() { + $scope.results = []; + restAPISvc + .getRestAPI( + "/api/submission/", + function(data) { + $scope.submissions = data; + $scope.submissionsForDisplay = []; + angular + .forEach( + $scope.submissions, + function( + submissionData) { + var temp = "id: " + + submissionData.submissionId + + " blueprint: " + + submissionData.blueprintInstance.blueprint.blueprintName + + " version: " + + submissionData.blueprintInstance.version + + " layer: " + + submissionData.blueprintInstance.layer + + " lab: " + + submissionData.blueprintInstance.timeslot.lab + + " Start date and time: " + + submissionData.blueprintInstance.timeslot.startDateTime + + " duration: " + + submissionData.blueprintInstance.timeslot.duration; + $scope.submissionsForDisplay + .push(temp); + }); + }); + } + $scope.selectedSubmissionChange = function( + selectedSubmission) { + $scope.results = []; + var id = selectedSubmission.substring( + selectedSubmission.indexOf("id:") + 4, + selectedSubmission.indexOf("blueprint") - 1); + restAPISvc.getRestAPI( + "/api/results/findBySubmissionId/" + id, + function(data) { + $scope.results = data; + }); + } + + }); \ No newline at end of file diff --git a/ui/src/main/webapp/resources/js/AECNewSubmissionController.js b/ui/src/main/webapp/resources/js/AECNewSubmissionController.js new file mode 100644 index 0000000..1cfafc4 --- /dev/null +++ b/ui/src/main/webapp/resources/js/AECNewSubmissionController.js @@ -0,0 +1,151 @@ +/* + * Copyright (c) 2019 AT&T Intellectual Property. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +var AECBlueprintValidationUIApp = angular + .module('BlueprintValidationUIManagement'); + +AECBlueprintValidationUIApp + .controller( + 'AECNewSubmissionController', + function($scope, appContext, restAPISvc) { + + initialize(); + + function initialize() { + restAPISvc + .getRestAPI( + "/api/blueprintInstance/", + function(data) { + $scope.blueprintInstances = data; + $scope.blueprintNames = []; + angular + .forEach( + $scope.blueprintInstances, + function( + blueprintInstance) { + if ($scope.blueprintNames + .indexOf(blueprintInstance["blueprint"]["blueprintName"]) === -1) { + $scope.blueprintNames + .push(blueprintInstance["blueprint"]["blueprintName"]); + } + }); + }); + } + $scope.selectedBluePrintNameChange = function() { + $scope.blueprintVersions = []; + $scope.blueprintLayers = []; + $scope.declerativeTimeslots = []; + angular + .forEach( + $scope.blueprintInstances, + function(blueprintInstance) { + if ($scope.selectedBlueprintName === blueprintInstance["blueprint"]["blueprintName"]) { + if ($scope.blueprintVersions + .indexOf(blueprintInstance["version"]) === -1) { + $scope.blueprintVersions + .push(blueprintInstance["version"]); + } + } + }); + } + $scope.selectedBluePrintVersionChange = function() { + $scope.blueprintLayers = []; + $scope.declerativeTimeslots = []; + angular + .forEach( + $scope.blueprintInstances, + function(blueprintInstance) { + if ($scope.selectedBlueprintName === blueprintInstance["blueprint"]["blueprintName"]) { + if ($scope.selectedBlueprintVersion === blueprintInstance["version"]) { + if ($scope.blueprintLayers + .indexOf(blueprintInstance["layer"]) === -1) { + $scope.blueprintLayers + .push(blueprintInstance["layer"]); + } + } + } + }); + } + $scope.selectedBluePrintLayerChange = function() { + $scope.declerativeTimeslots = []; + angular + .forEach( + $scope.blueprintInstances, + function(blueprintInstance) { + if ($scope.selectedBlueprintName === blueprintInstance["blueprint"]["blueprintName"]) { + if ($scope.selectedBlueprintVersion === blueprintInstance["version"]) { + if ($scope.selectedBlueprintLayer === blueprintInstance["layer"]) { + var temp = "id: " + + blueprintInstance["timeslot"].timeslotId + + " Start date and time: " + + blueprintInstance["timeslot"].startDateTime + + " duration(in sec) :" + + blueprintInstance["timeslot"].duration + + " lab :" + + blueprintInstance["timeslot"].lab; + if ($scope.declerativeTimeslots + .indexOf(temp) === -1) { + $scope.declerativeTimeslots + .push(temp); + } + } + } + } + }); + } + $scope.submit = function() { + var finalBlueprint; + angular + .forEach( + $scope.blueprintInstances, + function(blueprintInstance) { + if (blueprintInstance["blueprint"]["blueprintName"] === $scope.selectedBlueprintName) { + if (blueprintInstance["version"] === $scope.selectedBlueprintVersion) { + if (blueprintInstance["layer"] === $scope.selectedBlueprintLayer) { + var selectedDeclerativeTimeslotId = $scope.selectedDeclerativeTimeslot + .substring( + $scope.selectedDeclerativeTimeslot + .indexOf("id:") + 4, + $scope.selectedDeclerativeTimeslot + .indexOf("Start date and time:") - 1); + if (selectedDeclerativeTimeslotId + .toString() + .trim() === blueprintInstance["timeslot"]["timeslotId"] + .toString() + .trim()) { + finalBlueprint = blueprintInstance; + } + } + } + } + }); + var submission = { + "blueprintInstance" : finalBlueprint + }; + restAPISvc + .postRestAPI( + "/api/submission/", + submission, + function(data) { + if (data !== undefined) { + confirm("Submission committed successfully"); + } else { + confirm("Error when committing the submission"); + } + }); + } + + }); diff --git a/ui/src/main/webapp/resources/js/App.Config.js b/ui/src/main/webapp/resources/js/App.Config.js new file mode 100644 index 0000000..8fb450a --- /dev/null +++ b/ui/src/main/webapp/resources/js/App.Config.js @@ -0,0 +1,19 @@ +/* + * Copyright (c) 2019 AT&T Intellectual Property. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +var config_module = angular.module('App.config', []); +config_module.constant('appContext', '/AECBlueprintValidationUI'); +config_module.constant('refreshPeriod', '5000'); // in msecs diff --git a/ui/src/main/webapp/resources/js/App.Services.js b/ui/src/main/webapp/resources/js/App.Services.js new file mode 100644 index 0000000..f0887ad --- /dev/null +++ b/ui/src/main/webapp/resources/js/App.Services.js @@ -0,0 +1,109 @@ +/* + * Copyright (c) 2019 AT&T Intellectual Property. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +var AECBlueprintValidationUIApp = angular + .module('BlueprintValidationUIManagement'); + +AECBlueprintValidationUIApp.factory('restAPISvc', [ + '$http', + 'appContext', + function($http, appContext) { + var svc = []; + svc.getRestAPI = function(path, cb) { + return $http({ + method : 'GET', + url : appContext + path, + headers : { + 'Content-Type' : "application/json", + 'Accept' : "application/json" + } + }).then( + function(response) { + if (response.status == 200) { + cb(response.data); + } else { + /* eslint-disable no-console */ + console.log("Get REST API error: " + + response.statusText); + /* eslint-enable no-console */ + cb(null); + } + }, + function(error) { + /* eslint-disable no-console */ + console.log("Get REST API error: " + + error.statusText); + /* eslint-enable no-console */ + cb(null); + }); + }; + svc.postRestAPI = function(path, json, cb) { + return $http({ + method : 'POST', + url : appContext + path, + headers : { + 'Content-Type' : "application/json", + 'Accept' : "application/json" + }, + data : json + }).then( + function(response) { + if (response.status == 200 + || response.status == 201) { + cb(response.data); + } else { + /* eslint-disable no-console */ + console.log("Post REST API error: " + + response.statusText); + /* eslint-enable no-console */ + cb(null); + } + }, + function(error) { + /* eslint-disable no-console */ + console.log("Post REST API error: " + + error.statusText); + /* eslint-enable no-console */ + cb(null); + }); + }; + svc.deleteRestAPI = function(path, json) { + return $http({ + method : 'DELETE', + url : appContext + path, + headers : { + 'Content-Type' : "application/json", + 'Accept' : "application/json" + }, + data : json + }).then( + function(response) { + if (response.status !== 200) { + /* eslint-disable no-console */ + console.log("Delete REST API error: " + + response.statusText); + /* eslint-enable no-console */ + } + }, + function(error) { + /* eslint-disable no-console */ + console.log("Delete REST API error: " + + error.statusText); + /* eslint-enable no-console */ + }); + }; + return svc; + } ]); \ No newline at end of file diff --git a/ui/src/main/webapp/resources/js/App.js b/ui/src/main/webapp/resources/js/App.js new file mode 100755 index 0000000..1bc514c --- /dev/null +++ b/ui/src/main/webapp/resources/js/App.js @@ -0,0 +1,147 @@ +/* + * Copyright (c) 2019 AT&T Intellectual Property. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +var AECBlueprintValidationUIApp = angular.module('BlueprintValidationUIManagement', ['ngDialog', 'ui.router', 'base64','App.config','ngStorage','ui.bootstrap', 'ngResource','ngFileUpload','ngMaterial']); + +AECBlueprintValidationUIApp.config(function($stateProvider, $urlRouterProvider) { + $urlRouterProvider.otherwise('/login') + $stateProvider + .state('common', { + templateUrl: 'views/indexMain.html', + abstract: true + }) + .state('login', { + url: "/login", + controller: 'Login', + templateUrl: 'views/login.html' + }) + .state('newSubmission', { + url: "/newSubmission", + parent: "common", + views: { + "main": { + controller: 'AECNewSubmissionController', + templateUrl: 'views/newSubmission.html' + } + } + }) + .state('committedSubmissions', { + url: "/committedSubmissions", + parent: "common", + views: { + "main": { + controller: 'AECCommittedSubmissionsController', + templateUrl: 'views/committedSubmissions.html' + } + } + }) + .state('findBySubmissionId', { + url: "/findBySubmissionId", + parent: "common", + views: { + "main": { + controller: 'AECFindBySubmissionIdController', + templateUrl: 'views/findBySubmissionId.html' + } + } + }) +}); + +AECBlueprintValidationUIApp.controller('Login',function($scope, $http, $filter, filterFilter, $state, $base64,$rootScope,$controller,appContext) { + $rootScope.tokenId =""; + $scope.usernameVal = ''; + $scope.passwordVal = ''; + $rootScope.message = "Please enter credentials"; + $scope.$state = $state; + + var baseURL = window.location.protocol + '//' + window.location.host; + /* eslint-disable no-console */ + console.log('Base URL for current frame is: ' + baseURL); + /* eslint-enable no-console */ + $scope.goLogin = function() { + var arr = $scope.passwordVal; + if ($scope.usernameVal == '' && $scope.passwordVal == '') { + $scope.userMessage = 'Please enter a username.'; + $scope.passwordMessage = 'Please enter a password.'; + } else if ($scope.usernameVal == '') { + $scope.userMessage = 'Please enter a username.'; + $scope.passwordMessage = ''; + } else if ($scope.passwordVal == '') { + $scope.passwordMessage = 'Please enter a password.'; + $scope.userMessage = ''; + } else if (arr.length < 6) { + $scope.passwordMessage = 'Please enter a valid password.'; + $scope.userMessage = ''; + } + else { + $scope.passwordMessage = ''; + $scope.userMessage =''; + // var userPwd = $scope.usernameVal + ":" + $scope.passwordVal; + // var auth = $base64.encode(userPwd); + /* + * $http({ method: 'POST', url: appContext+'/login', //url: + * 'http://'+hostUrl+'/AECPortalMgmt/login', headers: { + * 'Authorization': "Basic " + auth, 'Content-Type': + * "application/json", 'Accept': "application/json" }, data: { } }). + * then(function(response) { if (response.data.statusCode == 200) { + * $rootScope.tokenId = response.data.tokenId; + * localStorage.setItem("tokenId",response.data.tokenId); + * $state.transitionTo('sites'); } else if (response.data.statusCode == + * 401){ $scope.passwordVal= null; $scope.passwordMessage = 'Invalid + * Credentials, please try again...'; + * + * localStorage.removeItem("tokenId"); } }, function(error) { if + * (error.status == 401) { $scope.passwordMessage = 'Invalid + * Credentials, please try again...'; $scope.passwordVal =""; + * localStorage.removeItem("tokenId"); } else if (error.status == + * 400) { $scope.passwordMessage = 'Session Invalid, please login + * again...'; $scope.passwordVal =""; + * localStorage.removeItem("tokenId"); } else if (error.status == + * 307) { $scope.passwordMessage = 'Session expired,Please try + * again...'; $scope.passwordVal =""; + * localStorage.removeItem("tokenId"); } }); + */ + $state.transitionTo('committedSubmissions'); + } + } + $scope.goLogout = function() { + $http({ + method: 'POST', + url: appContext+'/logout', + headers: { + 'Content-Type': "application/json", + 'Accept': "application/json", + 'tokenId' : $rootScope.tokenId + }, + data:{ + } + /* + * data: { 'username': $scope.usernameVal, 'passowrd': + * $scope.passwordVal } + */ + }).then(function(response) { + if (response.data.statusCode == 200) { + $rootScope.tokenId =""; + localStorage.removeItem("tokenId"); + $state.transitionTo('login'); + $rootScope.message = 'User logged out, please login again...'; + } + }, function(response) { + $scope.message = 'Unknown error,Try again later' + response.status; + }); + } +}); + diff --git a/ui/src/main/webapp/resources/js/CommonController.js b/ui/src/main/webapp/resources/js/CommonController.js new file mode 100644 index 0000000..dda7718 --- /dev/null +++ b/ui/src/main/webapp/resources/js/CommonController.js @@ -0,0 +1,54 @@ +/* + * Copyright (c) 2019 AT&T Intellectual Property. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +var AECBlueprintValidationUIApp = angular + .module('BlueprintValidationUIManagement'); + +AECBlueprintValidationUIApp.controller('CommonController', function($scope, + $http, $sce, ngDialog, $filter, $rootScope, $state, $templateCache) { + $scope.errorHandle = function(error) { + if (error.status == 400) { + localStorage.removeItem("tokenId"); + $state.transitionTo('login'); + localStorage.removeItem("tokenId"); + $rootScope.message = 'Session Invalid, please login again...'; + } else if (error.status == 401) { + localStorage.removeItem("tokenId"); + $state.transitionTo('login'); + $rootScope.message = 'Invalid Credentials, please try again...'; + } else if (error.status == 307) { + localStorage.removeItem("tokenId"); + $state.transitionTo('login'); + $rootScope.message = 'Session expired,Please try again...'; + } + } + + $scope.$on('onBeforeUnload', function(e, confirmation) { + var e2 = e || window.event; + if (e2) { + confirmation.message = "All data willl be lost."; + e2.preventDefault(); + } + }); + $scope.$on('onUnload', function() { + $templateCache.removeAll(); + }); + + $scope.cmp = function(x, y) { + return x > y ? 1 : x < y ? -1 : 0; + }; + +}); \ No newline at end of file diff --git a/ui/src/main/webapp/reusable_chart.js b/ui/src/main/webapp/reusable_chart.js new file mode 100644 index 0000000..01ab32d --- /dev/null +++ b/ui/src/main/webapp/reusable_chart.js @@ -0,0 +1,127 @@ +d3.custom = {}; + +d3.custom.barChart = function module() { + var margin = { + top : 20, + right : 20, + bottom : 40, + left : 40 + }, width = 500, height = 500, gap = 0, ease = 'cubic-in-out'; + var svg, duration = 500; + + var dispatch = d3.dispatch('customHover'); + function exports(_selection) { + _selection + .each(function(_data) { + + var chartW = width - margin.left - margin.right, chartH = height + - margin.top - margin.bottom; + + var x1 = d3.scale.ordinal().domain( + _data.map(function(d, i) { + return i; + })).rangeRoundBands([ 0, chartW ], .1); + + var y1 = d3.scale.linear().domain( + [ 0, d3.max(_data, function(d, i) { + return d; + }) ]).range([ chartH, 0 ]); + + var xAxis = d3.svg.axis().scale(x1).orient('bottom'); + + var yAxis = d3.svg.axis().scale(y1).orient('left'); + + var barW = chartW / _data.length; + + if (!svg) { + svg = d3.select(this).append('svg').classed('chart', + true); + var container = svg.append('g').classed( + 'container-group', true); + container.append('g').classed('chart-group', true); + container.append('g') + .classed('x-axis-group axis', true); + container.append('g') + .classed('y-axis-group axis', true); + } + + svg.transition().duration(duration).attr({ + width : width, + height : height + }) + svg.select('.container-group').attr( + { + transform : 'translate(' + margin.left + ',' + + margin.top + ')' + }); + + svg.select('.x-axis-group.axis').transition().duration( + duration).ease(ease).attr({ + transform : 'translate(0,' + (chartH) + ')' + }).call(xAxis); + + svg.select('.y-axis-group.axis').transition().duration( + duration).ease(ease).call(yAxis); + + var gapSize = x1.rangeBand() / 100 * gap; + var barW = x1.rangeBand() - gapSize; + var bars = svg.select('.chart-group').selectAll('.bar') + .data(_data); + bars.enter().append('rect').classed('bar', true).attr({ + x : chartW, + width : barW, + y : function(d, i) { + return y1(d); + }, + height : function(d, i) { + return chartH - y1(d); + } + }).on('mouseover', dispatch.customHover); + bars.transition().duration(duration).ease(ease).attr({ + width : barW, + x : function(d, i) { + return x1(i) + gapSize / 2; + }, + y : function(d, i) { + return y1(d); + }, + height : function(d, i) { + return chartH - y1(d); + } + }); + bars.exit().transition().style({ + opacity : 0 + }).remove(); + + duration = 500; + + }); + } + exports.width = function(_x) { + if (!arguments.length) + return width; + width = parseInt(_x); + return this; + }; + exports.height = function(_x) { + if (!arguments.length) + return height; + height = parseInt(_x); + duration = 0; + return this; + }; + exports.gap = function(_x) { + if (!arguments.length) + return gap; + gap = _x; + return this; + }; + exports.ease = function(_x) { + if (!arguments.length) + return ease; + ease = _x; + return this; + }; + d3.rebind(exports, dispatch, 'on'); + return exports; +}; \ No newline at end of file diff --git a/ui/src/main/webapp/views/committedSubmissions.html b/ui/src/main/webapp/views/committedSubmissions.html new file mode 100644 index 0000000..a3d1072 --- /dev/null +++ b/ui/src/main/webapp/views/committedSubmissions.html @@ -0,0 +1,196 @@ + + + + + + + + +
+
+

Committed Submissions

+
+ +
+
+ +
+
+
+
+
+
+ +
+ +
+ Refresh + + +
+
+
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + +
 Id Status Blueprint VersionLayer Desired Timeslot Url of result 
 {{ + submission.submissionId }}{{ + submission.submissionStatus }}{{ + submission.blueprintInstance.blueprint.blueprintName }}{{ + submission.blueprintInstance.version }} + {{ + submission.blueprintInstance.layer }} + Lab: + {{ submission.blueprintInstance.timeslot.lab }} Start date and + time: {{ submission.blueprintInstance.timeslot.startDateTime }} + duration(in sec) : + {{submission.blueprintInstance.timeslot.duration}} + {{ + submission.nexusResultUrl }} +
+

+ +
+ + + + + + + \ No newline at end of file diff --git a/ui/src/main/webapp/views/findBySubmissionId.html b/ui/src/main/webapp/views/findBySubmissionId.html new file mode 100644 index 0000000..2900b25 --- /dev/null +++ b/ui/src/main/webapp/views/findBySubmissionId.html @@ -0,0 +1,182 @@ + + + + + + + + +
+
+

Find results by submission

+
+ + +
+ +
+ +
+ +

Test info

+

+

Name: {{result.name}}

+

Generated: {{result.robot.generated}}

+

Generator: {{result.robot.generator}}

+

Errors: {{result.robot.errors}}

+ +

Test Statistics

+

+ + + + + + + + + + + + + + + + + + + +
+

+
 Total statistics Total Pass Fail Pass / Fail 
{{ + stat.content }}{{ + (stat.fail * 1) + (stat.pass*1) }}{{ + stat.pass }}{{ + stat.fail}} +
+
+
+
+
+ + + + + + + + + + + + + + + + + + + + +
+

+
 Statistics by Tag Total Pass Fail Pass / Fail 
{{ + stat.content }}{{ + (stat.fail * 1) + (stat.pass*1) }}{{ + stat.pass }}{{ + stat.fail}} +
+
+
+
+
+ + + + + + + + + + + + + + + + + + + + +
+

+
 Statistics by Suite Total Pass Fail Pass / Fail 
{{ + stat.content }}{{ + (stat.fail * 1) + (stat.pass*1) }}{{ + stat.pass }}{{ + stat.fail}} +
+
+
+
+
+ +
+
+ + + + diff --git a/ui/src/main/webapp/views/indexMain.html b/ui/src/main/webapp/views/indexMain.html new file mode 100644 index 0000000..758bb3a --- /dev/null +++ b/ui/src/main/webapp/views/indexMain.html @@ -0,0 +1,117 @@ + + + diff --git a/ui/src/main/webapp/views/login.html b/ui/src/main/webapp/views/login.html new file mode 100644 index 0000000..daf5454 --- /dev/null +++ b/ui/src/main/webapp/views/login.html @@ -0,0 +1,98 @@ + +--> + + + + + + + +
+
+

Blueprint + Validation UI

+

Sign In Page

+
+
+
+
+ + +
+
+ +
+
+
+ +
+
+
+
+
+ + \ No newline at end of file diff --git a/ui/src/main/webapp/views/newSubmission.html b/ui/src/main/webapp/views/newSubmission.html new file mode 100644 index 0000000..11c8afa --- /dev/null +++ b/ui/src/main/webapp/views/newSubmission.html @@ -0,0 +1,68 @@ + + + + + + + +
+
+

Submission form

+
+ + +
+ +
+ + +
+ +
+ + +
+ +
+ + +
+ +
+ +
+ +
+ + + + + +