diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 0000000000000000000000000000000000000000..8f62c3cd2d7b99e025c70f9a6a54b5701f0d49b0 --- /dev/null +++ b/.dockerignore @@ -0,0 +1,4 @@ +# CI artifacts +archives +src/oai_rules_result* +*.html diff --git a/.gitmodules b/.gitmodules index 56724854b677cb1ab0b52c09f690aee564cfb519..d18b52ca55a0860c931156de756b7c28c22d9775 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,9 +1,9 @@ [submodule "src/oai-cn5g-common-src"] path = src/oai-cn5g-common-src url = https://gitlab.eurecom.fr/oai/cn5g/oai-cn5g-common-src.git -[submodule "build/build-common"] - path = build/build-common +[submodule "build/common-build"] + path = build/common-build url = https://gitlab.eurecom.fr/oai/cn5g/oai-cn5g-common-build.git [submodule "ci-scripts/common-ci"] - path = ci-scripts/common-ci + path = ci-scripts/common url = https://gitlab.eurecom.fr/oai/cn5g/oai-cn5g-common-ci.git diff --git a/CHANGELOG.md b/CHANGELOG.md index df9c533055dc5fa278b3921e2176af395882589d..e656860b44d6abbe9777eb719b33e65e9c73b4fd 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,15 @@ # RELEASE NOTES: # +## v1.5.1 -- May 2023 ## + +* Add HTTP/2 support +* Code Refactoring for: + * Logging mechanism (runtime log level selection) + * Installation / build scripts + * Continuous Integration scripts +* Published image on Docker-Hub is using now Ubuntu-20 as base image + * We will soon obsolete the build system for Ubuntu18.04 + ## v1.5.0 -- January 2023 ## * Initial release diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index ef94fc8e6bb3f5d63d0eea2907eb2e5e8bbbb876..2548db239e35ec061b6391d2d84ced76f1909eac 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -15,6 +15,19 @@ Please refer to the steps described on our website: [How to contribute to OAI](h * The Continuous Integration will reject your pull request. - All pull requests SHALL have **`develop`** branch as target branch. +## Synchronizing GIT sub-modules ## + +We are using nested GIT submodules. To synchronize them, the 2 most important commands to know are : + +1. `git submodule deinit --force .` +2. `git submodule update --init --recursive` + +If you have non-tracked files or modified files within git submodules, these commands may not work. + +Use the `--verbose` option to see the execution of each command. + +If the synchronization fails, you may need to go into the path of the failing git-submodule(s) and clean the workspace from non-tracked/modified files. + ## Coding Styles ## We are using `clang-format` as formatting tool on the C/C++ code. diff --git a/build/build-common b/build/build-common deleted file mode 160000 index 7ef996a4873ce487fb36da11325ae028974cc0df..0000000000000000000000000000000000000000 --- a/build/build-common +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 7ef996a4873ce487fb36da11325ae028974cc0df diff --git a/build/common-build b/build/common-build new file mode 160000 index 0000000000000000000000000000000000000000..63ebefe554a739ba1c686d5c2d70946b4af471c0 --- /dev/null +++ b/build/common-build @@ -0,0 +1 @@ +Subproject commit 63ebefe554a739ba1c686d5c2d70946b4af471c0 diff --git a/build/scripts/build_helper.pcf b/build/scripts/build_helper.pcf index 117bc6069864c9916c5a44841f26b840fa8520d7..35f8e2ae7b9875971c7aa6fbe8c06a15cac3d383 100644 --- a/build/scripts/build_helper.pcf +++ b/build/scripts/build_helper.pcf @@ -29,342 +29,13 @@ ################################ SCRIPT=$(readlink -f ${BASH_SOURCE}) THIS_SCRIPT_PATH=`dirname $SCRIPT` -source $THIS_SCRIPT_PATH/../build-common/installation/build_helper - -#------------------------------------------------------------------------------- -#arg1 is force (0 or 1) (no interactive script) -#arg2 is debug (0 or 1) (install debug libraries) -install_spdlog_from_git() { - echo "Starting to install spdlog" - if [ $1 -eq 0 ]; then - read -p "Do you want to install spdlog ? <y/N> " prompt - OPTION="" - else - prompt='y' - OPTION="-y" - fi - if [ $2 -eq 0 ]; then - debug=0 - else - debug=1 - fi - - - if [[ $prompt =~ [yY](es)* ]] - then - GIT_URL=https://github.com/gabime/spdlog.git - echo "Install spdlog from $GIT_URL" - pushd $OPENAIRCN_DIR/build/ext - echo "Downloading spdlog" - if [[ $OPTION =~ -[yY](es)* ]] - then - $SUDO rm -rf spdlog - fi - - git clone $GIT_URL - cd spdlog && git checkout v1.11.0 - ret=$?;[[ $ret -ne 0 ]] && popd && return $ret - - mkdir _build && cd _build - $CMAKE -G "Unix Makefiles" -DCMAKE_BUILD_TYPE=Release -DSPDLOG_FMT_EXTERNAL=ON -DSPDLOG_BUILD_SHARED=ON .. - make - ret=$?;[[ $ret -ne 0 ]] && popd && return $ret - $SUDO make install - ret=$?;[[ $ret -ne 0 ]] && popd && return $ret - popd - rm -Rf $OPENAIRCN_DIR/build/ext/spdlog/_build - fi - echo "spdlog installation complete" - return 0 -} - -#------------------------------------------------------------------------------- -#arg1 is force (0 or 1) (no interactive script) -#arg2 is debug (0 or 1) (install debug libraries) -install_fmt_from_git() { - echo "Starting to install fmt" - if [ $1 -eq 0 ]; then - read -p "Do you want to install fmt? <y/N> " prompt - OPTION="" - else - prompt='y' - OPTION="-y" - fi - if [ $2 -eq 0 ]; then - debug=0 - else - debug=1 - fi - - if [[ $prompt =~ [yY](es)* ]] - then - GIT_URL=https://github.com/fmtlib/fmt/ - echo "Install fmt from $GIT_URL" - pushd $OPENAIRCN_DIR/build/ext - echo "Downloading fmt" - if [[ $OPTION =~ -[yY](es)* ]] - then - $SUDO rm -rf fmt - fi - - git clone $GIT_URL - cd fmt && git checkout 9.0.0 - ret=$?;[[ $ret -ne 0 ]] && popd && return $ret - - mkdir _build && cd _build - $CMAKE -G "Unix Makefiles" -DFMT_TEST=OFF -DBUILD_SHARED_LIBS=TRUE .. - - make - ret=$?;[[ $ret -ne 0 ]] && popd && return $ret - $SUDO make install - ret=$?;[[ $ret -ne 0 ]] && popd && return $ret - popd - rm -Rf $OPENAIRCN_DIR/build/ext/fmt/_build - fi - echo "fmt installation complete" - return 0 -} - -#------------------------------------------------------------------------------- -#arg1 is force (0 or 1) (no interactive script) -#arg2 is debug (0 or 1) (install debug libraries) -install_pistache_from_git() { - echo "Starting to install pistache" - if [ $1 -eq 0 ]; then - read -p "Do you want to install Pistache ? <y/N> " prompt - OPTION="-y" - else - prompt='y' - OPTION="-y" - fi - if [ $2 -eq 0 ]; then - debug=0 - else - debug=1 - fi - - - if [[ $prompt =~ [yY](es)* ]] - then - GIT_URL=https://github.com/oktal/pistache.git - echo "Install Pistache from $GIT_URL" - pushd $OPENAIRCN_DIR/build/ext - echo "Downloading Pistache" - if [[ $OPTION =~ -[yY](es)* ]] - then - $SUDO rm -rf pistache - fi - - git clone $GIT_URL - cd pistache && git checkout e18ed9baeb2145af6f9ea41246cf48054ffd9907 - ret=$?;[[ $ret -ne 0 ]] && popd && return $ret - mkdir _build && cd _build - $CMAKE -G "Unix Makefiles" -DCMAKE_BUILD_TYPE=Release \ - -DPISTACHE_BUILD_EXAMPLES=false \ - -DPISTACHE_BUILD_TESTS=false \ - -DPISTACHE_BUILD_DOCS=false \ - .. - ret=$?;[[ $ret -ne 0 ]] && popd && return $ret - make -j $(nproc) - ret=$?;[[ $ret -ne 0 ]] && popd && return $ret - $SUDO make install - ret=$?;[[ $ret -ne 0 ]] && popd && return $ret - popd - rm -Rf $OPENAIRCN_DIR/build/ext/pistache/_build - fi - echo "pistache installation complete" - return 0 -} - -#------------------------------------------------------------------------------- -#arg1 is force (0 or 1) (no interactive script) -#arg2 is debug (0 or 1) (install debug libraries) -install_nlohmann_from_git() { - echo "Starting to install Nlohmann Json" - if [ $1 -eq 0 ]; then - read -p "Do you want to install Nlohmann Json ? <y/N> " prompt - OPTION="" - else - prompt='y' - OPTION="-y" - fi - if [ $2 -eq 0 ]; then - debug=0 - else - debug=1 - fi - - - if [[ $prompt =~ [yY](es)* ]] - then - GIT_URL=https://github.com/nlohmann/json.git - echo "Install Nlohmann Json from $GIT_URL" - pushd $OPENAIRCN_DIR/build/ext - echo "Downloading Nlohmann" - if [[ $OPTION =~ -[yY](es)* ]] - then - $SUDO rm -rf json - fi - - git clone $GIT_URL - cd json && git checkout -f v3.10.3 - ret=$?;[[ $ret -ne 0 ]] && popd && return $ret - mkdir _build && cd _build - $CMAKE -G "Unix Makefiles" -DCMAKE_BUILD_TYPE=Release -DJSON_BuildTests=OFF .. - ret=$?;[[ $ret -ne 0 ]] && popd && return $ret - make - ret=$?;[[ $ret -ne 0 ]] && popd && return $ret - $SUDO make install - ret=$?;[[ $ret -ne 0 ]] && popd && return $ret - popd - rm -Rf $OPENAIRCN_DIR/build/ext/json/_build - fi - echo "Nlohmann Json installation complete" - return 0 -} - -#------------------------------------------------------------------------------- -#arg1 is force (0 or 1) (no interactive script) -#arg2 is debug (0 or 1) (install debug libraries) -install_nghttp2_from_git() { - echo "Starting to install nghttp2" - if [ $1 -eq 0 ]; then - read -p "Do you want to install nghttp2 ? <y/N> " prompt - OPTION="" - else - prompt='y' - OPTION="-y" - fi - if [ $2 -eq 0 ]; then - debug=0 - else - debug=1 - fi - - - if [[ $prompt =~ [yY](es)* ]] - then - if [[ $OS_DISTRO == "ubuntu" ]]; then - PACKAGE_LIST="\ - g++ \ - $CMAKE \ - binutils \ - autoconf \ - automake \ - autotools-dev \ - libtool \ - pkg-config \ - zlib1g-dev \ - libcunit1-dev \ - libssl-dev \ - libxml2-dev libev-dev libevent-dev libjansson-dev libc-ares-dev \ - libjemalloc-dev libsystemd-dev python3-dev python-setuptools" - elif [[ "$OS_BASEDISTRO" == "fedora" ]]; then - PACKAGE_LIST="\ - gcc-c++ \ - binutils-devel \ - autoconf \ - automake \ - $CMAKE \ - make \ - libtool \ - pkg-config \ - zlib-devel \ - CUnit-devel \ - openssl-devel \ - libxml2-devel libev-devel libevent-devel jansson-devel c-ares-devel \ - jemalloc-devel systemd-devel python3-Cython python3-devel python3-setuptools" - else - echo_fatal "$OS_DISTRO is not a supported distribution." - fi - echo "Install build tools" - $SUDO $INSTALLER install $OPTION $PACKAGE_LIST - ret=$?;[[ $ret -ne 0 ]] && return $ret - - GIT_URL=https://github.com/nghttp2/nghttp2.git - echo "Install nghttp2 from $GIT_URL" - pushd $OPENAIRCN_DIR/build/ext - echo "Downloading nghttp2" - if [[ $OPTION =~ [yY](es)* ]] - then - $SUDO rm -rf nghttp2 - fi - - git clone $GIT_URL - cd nghttp2 - git checkout 43ba3125932c1d56addaeded2b7f62637af255cd - git submodule update --init - ret=$?;[[ $ret -ne 0 ]] && popd && return $ret - autoreconf -i - ret=$?;[[ $ret -ne 0 ]] && popd && return $ret - automake - ret=$?;[[ $ret -ne 0 ]] && popd && return $ret - autoconf - ret=$?;[[ $ret -ne 0 ]] && popd && return $ret - ./configure --enable-asio-lib --enable-lib-only - ret=$?;[[ $ret -ne 0 ]] && popd && return $ret - make -j $(nproc) - ret=$?;[[ $ret -ne 0 ]] && popd && return $ret - $SUDO make install - ret=$?;[[ $ret -ne 0 ]] && popd && return $ret - $SUDO ldconfig - ret=$?;[[ $ret -ne 0 ]] && popd && return $ret - git clean -x -d -ff . - popd - fi - echo "nghttp2 installation complete" - return 0 -} - -#------------------------------------------------------------------------------- -#arg1 is force (0 or 1) (no interactive script) -#arg2 is debug (0 or 1) (install debug libraries) -install_libyaml_cpp_from_git() { - # For Ubuntu 2x and RHEL we should install from repo. - echo "Starting to install libyaml_cpp" - if [ $1 -eq 0 ]; then - read -p "Do you want to install yaml_cpp ? <y/N> " prompt - OPTION="" - else - prompt='y' - OPTION="-y" - fi - if [ $2 -eq 0 ]; then - debug=0 - else - debug=1 - fi - - - if [[ $prompt =~ [yY](es)* ]] - then - GIT_URL=https://github.com/jbeder/yaml-cpp.git - echo "Install yaml-cpp from $GIT_URL" - pushd $OPENAIRCN_DIR/build/ext - echo "Downloading yaml-cpp" - if [[ $OPTION =~ -[yY](es)* ]] - then - $SUDO rm -rf yaml-cpp - fi - - git clone $GIT_URL - cd yaml-cpp && git checkout master - ret=$?;[[ $ret -ne 0 ]] && popd && return $ret - mkdir _build && cd _build - $CMAKE -G "Unix Makefiles" -DYAML_BUILD_SHARED_LIBS=on -DYAML_CPP_BUILD_TESTS=off .. - ret=$?;[[ $ret -ne 0 ]] && popd && return $ret - make - ret=$?;[[ $ret -ne 0 ]] && popd && return $ret - $SUDO make install - ret=$?;[[ $ret -ne 0 ]] && popd && return $ret - popd - rm -Rf $OPENAIRCN_DIR/build/ext/yaml-cpp/_build - fi - echo "yaml-cpp installation complete" - return 0 -} - - +source $THIS_SCRIPT_PATH/../common-build/installation/build_helper +source $THIS_SCRIPT_PATH/../common-build/installation/build_helper.fmt +source $THIS_SCRIPT_PATH/../common-build/installation/build_helper.spdlog +source $THIS_SCRIPT_PATH/../common-build/installation/build_helper.pistache +source $THIS_SCRIPT_PATH/../common-build/installation/build_helper.nlohmann +source $THIS_SCRIPT_PATH/../common-build/installation/build_helper.nghttp2 +source $THIS_SCRIPT_PATH/../common-build/installation/build_helper.yamlcpp #------------------------------------------------------------------------------- #arg1 is force (0 or 1) (no interactive script) @@ -515,6 +186,8 @@ check_install_pcf_deps() { install_nghttp2_from_git $1 $2 ret=$?;[[ $ret -ne 0 ]] && return $ret + # latest usage of yaml-cpp suggests that we should be using 0.7+ version + # To be sure, let's install from source all the time for the moment if [[ $OS_DISTRO == "ubuntu" ]]; then case "$(get_distribution_release)" in "ubuntu18.04") @@ -522,14 +195,22 @@ check_install_pcf_deps() { ret=$?;[[ $ret -ne 0 ]] && return $ret ;; "ubuntu20.04") - $SUDO $INSTALLER install $OPTION libyaml-cpp0.6 libyaml-cpp-dev + # definitely, 0.6.2 as PPA installed is not enough + install_libyaml_cpp_from_git $1 $2 + ret=$?;[[ $ret -ne 0 ]] && return $ret ;; "ubuntu22.04") - $SUDO $INSTALLER install $OPTION libyaml-cpp0.7 libyaml-cpp-dev + # not sure about 0.7.0 + #$SUDO $INSTALLER install $OPTION libyaml-cpp0.7 libyaml-cpp-dev + install_libyaml_cpp_from_git $1 $2 + ret=$?;[[ $ret -ne 0 ]] && return $ret ;; esac elif [[ "$OS_BASEDISTRO" == "fedora" ]]; then - $SUDO $INSTALLER install $OPTION yaml-cpp yaml-cpp-devel + # definitely, 0.6.2 as PPA installed is not enough + # $SUDO $INSTALLER install $OPTION yaml-cpp yaml-cpp-devel + install_libyaml_cpp_from_git $1 $2 + ret=$?;[[ $ret -ne 0 ]] && return $ret fi $SUDO ldconfig diff --git a/build/scripts/build_pcf b/build/scripts/build_pcf index f75b66725d935b373e13998995d75e6954989e57..1ea70b09f332a3364171734b39592e6e85f6491e 100755 --- a/build/scripts/build_pcf +++ b/build/scripts/build_pcf @@ -32,15 +32,25 @@ THIS_SCRIPT_PATH=$(dirname $(readlink -f $0)) ## initialize git submodules pushd ${THIS_SCRIPT_PATH}/../.. -git submodule update --init --recursive +if [ -d .git ] && [ -f .gitmodules ]; then + echo "Synchronizing the Git Sub-Modules" + git submodule status | while read -r line ; do + moduleName=`echo $line | awk '{print $2}'` + gitReference=`echo $line | awk '{print $3}'` + if [[ -z "$gitReference" ]]; then + echo "$moduleName looks empty!" + git submodule update --init --recursive $moduleName + fi + done + git submodule --quiet foreach 'echo "${path} is synchronized or in edition"' +fi popd INSTALL_DIR=/usr/local/bin ################################ # include helper functions ################################ -source $THIS_SCRIPT_PATH/build_helper.pcf - +source ${THIS_SCRIPT_PATH}/build_helper.pcf function help() { @@ -80,7 +90,9 @@ function main() -b | --build-type) list_include_item "Debug Release RelWithDebInfo MinSizeRel" $2 [[ $? -ne 0 ]] && echo_error "Build type $2 not recognized" && return $? + echo ${cmake_args} cmake_args="$cmake_args -DCMAKE_BUILD_TYPE=$2" + echo ${cmake_args} list_include_item "Debug" $2 [[ $? -ne 0 ]] && debug=1 shift 2; diff --git a/ci-scripts/Jenkinsfile-GitLab-Docker b/ci-scripts/Jenkinsfile-GitLab-Docker index 488a50db31fb65d58352f36f8e6c4a90558779fb..6fc29df85401c26702e1b49aa979579dc4e5cd36 100644 --- a/ci-scripts/Jenkinsfile-GitLab-Docker +++ b/ci-scripts/Jenkinsfile-GitLab-Docker @@ -213,7 +213,7 @@ pipeline { script { sh "sudo podman image prune --force" sh "rm -Rf ./etc-pki-entitlement ./rhsm-conf ./rhsm-ca" - stash includes: 'archives/pcf_podman_image_build.log', name: 'podmanBuildLog' + stash allowEmpty: true, includes: 'archives/pcf_podman_image_build.log', name: 'podmanBuildLog' } } } @@ -228,7 +228,8 @@ pipeline { // It's a different agent from main one. prepareWorkspaceMergeCase() // Moving to focal and cppcheck 1.90 and a dockerfile approach - sh 'docker build --target pcf-cppcheck --tag pcf-cppcheck:test --file ci-scripts/docker/Dockerfile.ci.cppcheck . > archives/cppcheck_install.log 2>&1' + sh 'sed -i -e "s@nfName@pcf@" ci-scripts/common/docker/Dockerfile.ci.cppcheck' + sh 'docker build --target pcf-cppcheck --tag pcf-cppcheck:test --file ci-scripts/common/docker/Dockerfile.ci.cppcheck . > archives/cppcheck_install.log 2>&1' sh 'docker run --name pcf-ci-cppcheck --entrypoint /bin/true pcf-cppcheck:test' sh 'docker cp pcf-ci-cppcheck:/home/cppcheck.xml archives' sh 'docker cp pcf-ci-cppcheck:/home/cppcheck_build.log archives' @@ -247,7 +248,7 @@ pipeline { } cleanup { script { - stash includes: 'archives/cppcheck*.*', name: 'cppcheckLogs' + stash allowEmpty: true, includes: 'archives/cppcheck*.*', name: 'cppcheckLogs' // no need to keep the cppcheck container sh 'docker rm -f pcf-ci-cppcheck || true' sh 'docker rmi pcf-cppcheck:test || true' @@ -264,10 +265,11 @@ pipeline { gitlabCommitStatus(name: "Code Formatting Checker") { // It's a different agent from main one. prepareWorkspaceMergeCase() + sh 'sed -i -e "s@nfName@pcf@" ci-scripts/common/docker/Dockerfile.ci.clang-format' if ("MERGE".equals(env.gitlabActionType)) { - sh 'docker build --target pcf-clang-format-check --tag pcf-clang-format-check:test --file ci-scripts/docker/Dockerfile.ci.clang-format --build-arg MERGE_REQUEST_CHECK=True --build-arg SOURCE_BRANCH=' + env.gitlabSourceBranch + ' --build-arg TARGET_BRANCH=' + env.gitlabTargetBranch + ' . > archives/clang_format_install.log 2>&1' + sh 'docker build --target pcf-clang-format-check --tag pcf-clang-format-check:test --file ci-scripts/common/docker/Dockerfile.ci.clang-format --build-arg MERGE_REQUEST_CHECK=True --build-arg SOURCE_BRANCH=' + env.gitlabSourceBranch + ' --build-arg TARGET_BRANCH=' + env.gitlabTargetBranch + ' . > archives/clang_format_install.log 2>&1' } else { - sh 'docker build --target pcf-clang-format-check --tag pcf-clang-format-check:test --file ci-scripts/docker/Dockerfile.ci.clang-format . > archives/clang_format_install.log 2>&1' + sh 'docker build --target pcf-clang-format-check --tag pcf-clang-format-check:test --file ci-scripts/common/docker/Dockerfile.ci.clang-format . > archives/clang_format_install.log 2>&1' } sh 'docker run --name pcf-ci-clang-format --entrypoint /bin/true pcf-clang-format-check:test' sh 'docker cp pcf-ci-clang-format:/home/src/oai_rules_result.txt src' @@ -283,7 +285,7 @@ pipeline { post { cleanup { script { - stash includes: 'src/oai_rules_result*.txt', name: 'formatCheckLogs' + stash allowEmpty: true, includes: 'src/oai_rules_result*.txt, archives/clang_format_install.log', name: 'formatCheckLogs' sh 'docker rm -f pcf-ci-clang-format || true' sh 'docker rmi pcf-clang-format-check:test || true' } @@ -317,8 +319,7 @@ pipeline { if (localStatus.resultIsBetterOrEqualTo('SUCCESS')) { echo "Tutorials Test Job is OK" } else { - echo "Tutorials Test Job is KO" - sh "ci-scripts/fail.sh" + error "Tutorials Test Job is KO" } } } @@ -389,9 +390,9 @@ pipeline { // Generating the HTML report(s) if ("MERGE".equals(env.gitlabActionType)) { - sh "python3 ci-scripts/generateHtmlReport.py --job_name=${JOB_NAME} --job_id=${BUILD_ID} --job_url=${BUILD_URL} --git_url=${GIT_URL} --git_src_branch=${env.gitlabSourceBranch} --git_src_commit=${env.gitlabMergeRequestLastCommit} --git_pull_request=True --git_target_branch=${env.gitlabTargetBranch} --git_target_commit=${GIT_COMMIT}" + sh "./ci-scripts/generateHtmlReport.py --job-name ${JOB_NAME} --build-id ${BUILD_ID} --build-url ${BUILD_URL} --git-url ${GIT_URL} --git-src-branch ${env.gitlabSourceBranch} --git-src-commit ${env.gitlabMergeRequestLastCommit} --git-merge-request --git-dst-branch ${env.gitlabTargetBranch} --git-dst-commit ${GIT_COMMIT}" } else { - sh "python3 ci-scripts/generateHtmlReport.py --job_name=${JOB_NAME} --job_id=${BUILD_ID} --job_url=${BUILD_URL} --git_url=${GIT_URL} --git_src_branch=${GIT_BRANCH} --git_src_commit=${GIT_COMMIT}" + sh "./ci-scripts/generateHtmlReport.py --job-name ${JOB_NAME} --build-id ${BUILD_ID} --build-url ${BUILD_URL} --git-url ${GIT_URL} --git-src-branch ${GIT_BRANCH} --git-src-commit ${GIT_COMMIT}" } listOfFiles = sh returnStdout: true, script: 'ls test_results*.html' String[] htmlFiles = listOfFiles.split("\\n") @@ -427,6 +428,8 @@ OAI CI Team''', def prepareWorkspaceMergeCase () { sh "git clean -x -d -f > /dev/null 2>&1" + sh "git submodule foreach --recursive 'git clean -x -d -ff' > /dev/null 2>&1" + sh "git submodule deinit --force --all > /dev/null 2>&1" if ("MERGE".equals(env.gitlabActionType)) { sh "./ci-scripts/doGitLabMerge.sh --src-branch ${env.gitlabSourceBranch} --src-commit ${env.gitlabMergeRequestLastCommit} --target-branch ${env.gitlabTargetBranch} --target-commit ${GIT_COMMIT}" } diff --git a/ci-scripts/checkCodingFormattingRules.sh b/ci-scripts/checkCodingFormattingRules.sh deleted file mode 100755 index 2e0d0d496861d0a53197129b3d410071288b93f9..0000000000000000000000000000000000000000 --- a/ci-scripts/checkCodingFormattingRules.sh +++ /dev/null @@ -1,208 +0,0 @@ -#!/bin/bash -#/* -# * Licensed to the OpenAirInterface (OAI) Software Alliance under one or more -# * contributor license agreements. See the NOTICE file distributed with -# * this work for additional information regarding copyright ownership. -# * The OpenAirInterface Software Alliance licenses this file to You under -# * the OAI Public License, Version 1.1 (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.openairinterface.org/?page_id=698 -# * -# * 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. -# *------------------------------------------------------------------------------- -# * For more information about the OpenAirInterface (OAI) Software Alliance: -# * contact@openairinterface.org -# */ - -function usage { - echo "OAI Coding / Formatting Guideline Check script" - echo " Original Author: Raphael Defosseux" - echo "" - echo " Requirement: clang-format / git shall be installed" - echo "" - echo " By default (no options) the complete repository will be checked" - echo " In case of merge/pull request, provided source and target branch," - echo " the script will check only the modified files" - echo "" - echo "Usage:" - echo "------" - echo " checkCodingFormattingRules.sh [OPTIONS]" - echo "" - echo "Options:" - echo "--------" - echo " --src-branch #### OR -sb ####" - echo " Specify the source branch of the merge request." - echo "" - echo " --target-branch #### OR -tb ####" - echo " Specify the target branch of the merge request (usually develop)." - echo "" - echo " --help OR -h" - echo " Print this help message." - echo "" -} - -if [ $# -ne 4 ] && [ $# -ne 1 ] && [ $# -ne 0 ] -then - echo "Syntax Error: not the correct number of arguments" - echo "" - usage - exit 1 -fi - -cd src - -if [ $# -eq 0 ] -then - echo " ---- Checking the whole repository ----" - echo "" - if [ -f oai_rules_result.txt ] - then - rm -f oai_rules_result.txt - fi - if [ -f oai_rules_result_list.txt ] - then - rm -f oai_rules_result_list.txt - fi - EXTENSION_LIST=("h" "hpp" "c" "cpp") - NB_TO_FORMAT=0 - NB_TOTAL=0 - for EXTENSION in ${EXTENSION_LIST[@]} - do - echo "Checking for all files with .${EXTENSION} extension" - FILE_LIST=`tree -n --noreport -i -f -P *.${EXTENSION} | sed -e 's#^\./##' | grep "\.${EXTENSION}"` - for FILE_TO_CHECK in ${FILE_LIST[@]} - do - TO_FORMAT=`clang-format -output-replacements-xml ${FILE_TO_CHECK} 2>&1 | grep -v replacements | grep -c replacement` - NB_TOTAL=$((NB_TOTAL + 1)) - if [ $TO_FORMAT -ne 0 ] - then - NB_TO_FORMAT=$((NB_TO_FORMAT + 1)) - # In case of full repo, being silent - #echo "src/$FILE_TO_CHECK" - echo "src/$FILE_TO_CHECK" >> ./oai_rules_result_list.txt - fi - done - done - echo "Nb Files that do NOT follow OAI rules: $NB_TO_FORMAT over $NB_TOTAL checked!" - echo "NB_FILES_FAILING_CHECK=$NB_TO_FORMAT" > ./oai_rules_result.txt - echo "NB_FILES_CHECKED=$NB_TOTAL" >> ./oai_rules_result.txt - exit 0 -fi - -checker=0 -while [[ $# -gt 0 ]] -do -key="$1" - -case $key in - -h|--help) - shift - usage - exit 0 - ;; - -sb|--src-branch) - SOURCE_BRANCH="$2" - let "checker|=0x1" - shift - shift - ;; - -tb|--target-branch) - TARGET_BRANCH="$2" - let "checker|=0x2" - shift - shift - ;; - *) - echo "Syntax Error: unknown option: $key" - echo "" - usage - exit 1 -esac - -done - - -if [ $checker -ne 3 ] -then - echo "Source Branch is : $SOURCE_BRANCH" - echo "Target Branch is : $TARGET_BRANCH" - echo "" - echo "Syntax Error: missing option" - echo "" - usage - exit 1 -fi - -# When running in a container, in /home folder -IS_CONTAINER=`egrep -c "docker|kubepods|podman|buildah|libpod" /proc/self/cgroup || true` -if [ $IS_CONTAINER -ne 0 ] -then - if [ $PWD = "/home/src" ] - then - git config --global --add safe.directory /home - fi -fi - -# Merge request scenario - -MERGE_COMMMIT=`git log -n1 --pretty=format:%H` -if [ -f .git/refs/remotes/origin/$TARGET_BRANCH ] -then - TARGET_INIT_COMMIT=`cat .git/refs/remotes/origin/$TARGET_BRANCH` -else - TARGET_INIT_COMMIT=`git log -n1 --pretty=format:%H origin/$TARGET_BRANCH` -fi - -echo " ---- Checking the modified files by the merge request ----" -echo "" -echo "Source Branch is : $SOURCE_BRANCH" -echo "Target Branch is : $TARGET_BRANCH" -echo "Merged Commit is : $MERGE_COMMMIT" -echo "Target Init is : $TARGET_INIT_COMMIT" -echo "" -echo " ----------------------------------------------------------" -echo "" - -# Retrieve the list of modified files since the latest develop commit -MODIFIED_FILES=`git log $TARGET_INIT_COMMIT..$MERGE_COMMMIT --oneline --name-status | egrep "^M|^A" | sed -e "s@^M\t*@@" -e "s@^A\t*@@" | sort | uniq` -NB_TO_FORMAT=0 -NB_TOTAL=0 - -if [ -f oai_rules_result.txt ] -then - rm -f oai_rules_result.txt -fi -if [ -f oai_rules_result_list.txt ] -then - rm -f oai_rules_result_list.txt -fi -for FULLFILE in $MODIFIED_FILES -do - filename=$(basename -- "$FULLFILE") - EXT="${filename##*.}" - if [ $EXT = "c" ] || [ $EXT = "h" ] || [ $EXT = "cpp" ] || [ $EXT = "hpp" ] - then - SRC_FILE=`echo $FULLFILE | sed -e "s#src/##"` - TO_FORMAT=`clang-format -output-replacements-xml ${SRC_FILE} 2>&1 | grep -v replacements | grep -c replacement` - NB_TOTAL=$((NB_TOTAL + 1)) - if [ $TO_FORMAT -ne 0 ] - then - NB_TO_FORMAT=$((NB_TO_FORMAT + 1)) - echo $FULLFILE - echo $FULLFILE >> ./oai_rules_result_list.txt - fi - fi -done -echo "" -echo " ----------------------------------------------------------" -echo "Nb Files that do NOT follow OAI rules: $NB_TO_FORMAT over $NB_TOTAL checked!" -echo "NB_FILES_FAILING_CHECK=$NB_TO_FORMAT" > ./oai_rules_result.txt -echo "NB_FILES_CHECKED=$NB_TOTAL" >> ./oai_rules_result.txt - -if [ $NB_TO_FORMAT -ne 0 ]; then exit -1; else exit 0; fi diff --git a/ci-scripts/common b/ci-scripts/common new file mode 160000 index 0000000000000000000000000000000000000000..b9ca1e67d3e4b4fee5075d90e98015698ab1f0a1 --- /dev/null +++ b/ci-scripts/common @@ -0,0 +1 @@ +Subproject commit b9ca1e67d3e4b4fee5075d90e98015698ab1f0a1 diff --git a/ci-scripts/common-ci b/ci-scripts/common-ci deleted file mode 160000 index c458e9dd6a5cbce1306680d4289012b8f493ff85..0000000000000000000000000000000000000000 --- a/ci-scripts/common-ci +++ /dev/null @@ -1 +0,0 @@ -Subproject commit c458e9dd6a5cbce1306680d4289012b8f493ff85 diff --git a/ci-scripts/docker/Dockerfile.ci.clang-format b/ci-scripts/docker/Dockerfile.ci.clang-format deleted file mode 100644 index a99a9dca38dead38b66e0a9422cc8119d0249d2d..0000000000000000000000000000000000000000 --- a/ci-scripts/docker/Dockerfile.ci.clang-format +++ /dev/null @@ -1,38 +0,0 @@ -#/* -# * Licensed to the OpenAirInterface (OAI) Software Alliance under one or more -# * contributor license agreements. See the NOTICE file distributed with -# * this work for additional information regarding copyright ownership. -# * The OpenAirInterface Software Alliance licenses this file to You under -# * the OAI Public License, Version 1.1 (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.openairinterface.org/?page_id=698 -# * -# * 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. -# *------------------------------------------------------------------------------- -# * For more information about the OpenAirInterface (OAI) Software Alliance: -# * contact@openairinterface.org -# */ -#--------------------------------------------------------------------- -# -FROM ubuntu:focal as pcf-clang-format-check -ARG MERGE_REQUEST_CHECK -ARG SOURCE_BRANCH -ARG TARGET_BRANCH - -RUN apt-get update && \ - apt-get upgrade -y && \ - apt-get install --yes \ - git \ - tree \ - clang-format-9 - -WORKDIR /home -COPY . . - -RUN /bin/bash -c "if [[ -v MERGE_REQUEST_CHECK ]]; then ./ci-scripts/checkCodingFormattingRules.sh --src-branch $SOURCE_BRANCH --target-branch $TARGET_BRANCH; else ./ci-scripts/checkCodingFormattingRules.sh; fi" diff --git a/ci-scripts/docker/Dockerfile.ci.cppcheck b/ci-scripts/docker/Dockerfile.ci.cppcheck deleted file mode 100644 index 84fc920f772e4e78c23433aedbf38c12fb59adc1..0000000000000000000000000000000000000000 --- a/ci-scripts/docker/Dockerfile.ci.cppcheck +++ /dev/null @@ -1,36 +0,0 @@ -#/* -# * Licensed to the OpenAirInterface (OAI) Software Alliance under one or more -# * contributor license agreements. See the NOTICE file distributed with -# * this work for additional information regarding copyright ownership. -# * The OpenAirInterface Software Alliance licenses this file to You under -# * the OAI Public License, Version 1.1 (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.openairinterface.org/?page_id=698 -# * -# * 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. -# *------------------------------------------------------------------------------- -# * For more information about the OpenAirInterface (OAI) Software Alliance: -# * contact@openairinterface.org -# */ -#--------------------------------------------------------------------- -# -FROM ubuntu:focal as pcf-cppcheck - -RUN apt-get update && \ - apt-get upgrade -y && \ - apt-get install --yes cppcheck - -WORKDIR /home -COPY . . - -RUN cppcheck --enable=warning --force \ - --xml --xml-version=2 \ - --suppressions-list=ci-scripts/cppcheck_suppressions.list src \ - 2> cppcheck.xml \ - 1> cppcheck_build.log diff --git a/ci-scripts/docker/Dockerfile.ci.ubuntu b/ci-scripts/docker/Dockerfile.ci.ubuntu deleted file mode 100644 index c1b4d47eec831cd9854c36412d27cb197a735b6f..0000000000000000000000000000000000000000 --- a/ci-scripts/docker/Dockerfile.ci.ubuntu +++ /dev/null @@ -1,123 +0,0 @@ -#/* -# * Licensed to the OpenAirInterface (OAI) Software Alliance under one or more -# * contributor license agreements. See the NOTICE file distributed with -# * this work for additional information regarding copyright ownership. -# * The OpenAirInterface Software Alliance licenses this file to You under -# * the OAI Public License, Version 1.1 (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.openairinterface.org/?page_id=698 -# * -# * 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. -# *------------------------------------------------------------------------------- -# * For more information about the OpenAirInterface (OAI) Software Alliance: -# * contact@openairinterface.org -# */ -#--------------------------------------------------------------------- -# -# Dockerfile for the Open-Air-Interface PCF service -# Valid for Ubuntu-18.04 (bionic) -# -#--------------------------------------------------------------------- - -#--------------------------------------------------------------------- -# BUILDER IMAGE -#--------------------------------------------------------------------- -ARG BASE_IMAGE=ubuntu:bionic -FROM oai-pcf-base:latest as oai-pcf-builder - -RUN rm -Rf /openair-pcf -# Copying source code -WORKDIR /openair-pcf -COPY . /openair-pcf - -# Building PCF -WORKDIR /openair-pcf/build/scripts -RUN ldconfig && \ - cp -Rf /openair-pcf-ext-ref /openair-pcf/build/ext && \ - ./build_pcf --clean --Verbose --build-type Release --jobs && \ - ldd /openair-pcf/build/pcf/build/pcf && \ - mv /openair-pcf/build/pcf/build/pcf /openair-pcf/build/pcf/build/oai_pcf - -#--------------------------------------------------------------------- -# TARGET IMAGE -#--------------------------------------------------------------------- -FROM $BASE_IMAGE as oai-pcf -ENV DEBIAN_FRONTEND=noninteractive -ENV TZ=Europe/Paris -# We install some debug tools for the moment in addition of mandatory libraries -RUN apt-get update && \ - DEBIAN_FRONTEND=noninteractive apt-get upgrade --yes && \ - DEBIAN_FRONTEND=noninteractive apt-get install --yes \ - python3 \ - python3-jinja2 \ - psmisc \ - net-tools \ - tzdata \ - bc \ - openssl \ -# Ubuntu 18 --> libasan4 -# Ubuntu 20 --> libasan5 -# Ubuntu 22 --> libasan6 -# libasan? \ -# Ubuntu 18 --> boost62/65 -> will remove both -# Ubuntu 20 --> boost67/71 -> will remove 67 -# Ubuntu 22 --> boost74 - libboost-filesystem1.??.0 \ - libcurl?-gnutls \ - librtmp1 \ - libpsl5 \ -# Ubuntu 18 --> won't install anything -# Ubuntu 20 --> libyaml-cpp 0.6 -# Ubuntu 22 --> libyaml-cpp 0.7 - libyaml-cpp0.? \ - && rm -rf /var/lib/apt/lists/* \ - /lib/x86_64-linux-gnu/libboost_system.so.1.6*.0 \ - /lib/x86_64-linux-gnu/ibboost_filesystem.so.1.6*.0 - -# Copying executable and generated libraries -WORKDIR /openair-pcf/bin -COPY --from=oai-pcf-builder \ - /openair-pcf/build/pcf/build/oai_pcf \ - /openair-pcf/scripts/healthcheck.sh \ - ./ - -WORKDIR /usr/local/lib/ -COPY --from=oai-pcf-builder \ -# Copying only the packages built from source - /usr/local/lib/libpistache.so \ - /usr/local/lib/libnghttp2.so.14 \ - /usr/local/lib/libnghttp2_asio.so.1 \ - /usr/local/lib/libyaml-cpp.so.0.? \ - /usr/local/lib/libspdlog.so \ - /usr/local/lib/libfmt.so \ -# Ubuntu 18 --> boost 67 will be copied - /usr/lib/libboost_system.so.1.* \ - /usr/lib/libboost_filesystem.so.1.* \ - ./ - -RUN ldconfig && \ - ldd /openair-pcf/bin/oai_pcf - -# Copying template configuration files -# The configuration folder will be flat -WORKDIR /openair-pcf/etc -COPY --from=oai-pcf-builder \ - /openair-pcf/etc/config.yaml \ - ./ - -WORKDIR /openair-pcf - -EXPOSE 80/tcp 8080/tcp -# healthcheck -HEALTHCHECK --interval=10s \ - --timeout=15s \ - --retries=6 \ - CMD /openair-pcf/bin/healthcheck.sh - -CMD ["/openair-pcf/bin/oai_pcf", "-c", "/openair-pcf/etc/config.yaml", "-o"] diff --git a/ci-scripts/generateHtmlReport.py b/ci-scripts/generateHtmlReport.py old mode 100644 new mode 100755 index 72badb995373726d68a084a40ef019271cbd821a..a268b04d3cc99b9c4e520dba8087b3bb3d487654 --- a/ci-scripts/generateHtmlReport.py +++ b/ci-scripts/generateHtmlReport.py @@ -1,940 +1,89 @@ -#/* -# * Licensed to the OpenAirInterface (OAI) Software Alliance under one or more -# * contributor license agreements. See the NOTICE file distributed with -# * this work for additional information regarding copyright ownership. -# * The OpenAirInterface Software Alliance licenses this file to You under -# * the OAI Public License, Version 1.1 (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.openairinterface.org/?page_id=698 -# * -# * 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. -# *------------------------------------------------------------------------------- -# * For more information about the OpenAirInterface (OAI) Software Alliance: -# * contact@openairinterface.org -# */ -#--------------------------------------------------------------------- - -import glob +#!/usr/bin/env python3 +""" +Licensed to the OpenAirInterface (OAI) Software Alliance under one or more +contributor license agreements. See the NOTICE file distributed with +this work for additional information regarding copyright ownership. +The OpenAirInterface Software Alliance licenses this file to You under +the OAI Public License, Version 1.1 (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.openairinterface.org/?page_id=698 + +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. +------------------------------------------------------------------------------ +For more information about the OpenAirInterface (OAI) Software Alliance: + contact@openairinterface.org +--------------------------------------------------------------------- +""" + +#import argparse import os import re -import sys -import subprocess - -class HtmlReport(): - def __init__(self): - self.job_name = '' - self.job_id = '' - self.job_url = '' - self.job_start_time = 'TEMPLATE_TIME' - self.git_url = '' - self.git_src_branch = '' - self.git_src_commit = '' - self.git_src_commit_msg = None - self.git_pull_request = False - self.git_target_branch = '' - self.git_target_commit = '' - self.nb_warnings = 0 - self.warning_rows = '' - - def generate(self): - cwd = os.getcwd() - self.file = open(cwd + '/test_results_oai_pcf.html', 'w') - self.generateHeader() - - self.coding_formatting_log() - - self.analyze_sca_log() - - self.buildSummaryHeader() - self.initialGitSetup() - self.installLibsPackagesRow() - self.buildCompileRows() - self.copyToTargetImage() - self.copyConfToolsToTargetImage() - self.imageSizeRow() - self.buildSummaryFooter() - - self.generateFooter() - self.file.close() - - def generateHeader(self): - # HTML Header - self.file.write('<!DOCTYPE html>\n') - self.file.write('<html class="no-js" lang="en-US">\n') - self.file.write('<head>\n') - self.file.write(' <meta name="viewport" content="width=device-width, initial-scale=1">\n') - self.file.write(' <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css">\n') - self.file.write(' <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>\n') - self.file.write(' <script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js"></script>\n') - self.file.write(' <title>OAI Core Network Test Results for ' + self.job_name + ' job build #' + self.job_id + '</title>\n') - self.file.write('</head>\n') - self.file.write('<body><div class="container">\n') - self.file.write(' <table width = "100%" style="border-collapse: collapse; border: none;">\n') - self.file.write(' <tr style="border-collapse: collapse; border: none;">\n') - self.file.write(' <td style="border-collapse: collapse; border: none;">\n') - self.file.write(' <a href="http://www.openairinterface.org/">\n') - self.file.write(' <img src="http://www.openairinterface.org/wp-content/uploads/2016/03/cropped-oai_final_logo2.png" alt="" border="none" height=50 width=150>\n') - self.file.write(' </img>\n') - self.file.write(' </a>\n') - self.file.write(' </td>\n') - self.file.write(' <td style="border-collapse: collapse; border: none; vertical-align: center;">\n') - self.file.write(' <b><font size = "6">Job Summary -- Job: ' + self.job_name + ' -- Build-ID: <a href="' + self.job_url + '">' + self.job_id + '</a></font></b>\n') - self.file.write(' </td>\n') - self.file.write(' </tr>\n') - self.file.write(' </table>\n') - self.file.write(' <br>\n') - - # Build Info Summary - buildSummary = '' - buildSummary += ' <table class="table-bordered" width = "80%" align = "center" border = "1">\n' - buildSummary += ' <tr>\n' - buildSummary += ' <td bgcolor="lightcyan" > <span class="glyphicon glyphicon-time"></span> Build Start Time</td>\n' - #date_formatted = re.sub('\..*', '', self.created) - buildSummary += ' <td>' + self.job_start_time + '</td>\n' - buildSummary += ' </tr>\n' - buildSummary += ' <tr>\n' - buildSummary += ' <td bgcolor="lightcyan" > <span class="glyphicon glyphicon-wrench"></span> Build Trigger</td>\n' - if self.git_pull_request: - buildSummary += ' <td>Pull Request</td>\n' - else: - buildSummary += ' <td>Push Event</td>\n' - buildSummary += ' </tr>\n' - buildSummary += ' <tr>\n' - buildSummary += ' <td bgcolor="lightcyan" > <span class="glyphicon glyphicon-cloud-upload"></span> GIT Repository</td>\n' - buildSummary += ' <td><a href="' + self.git_url + '">' + self.git_url + '</a></td>\n' - buildSummary += ' </tr>\n' - if self.git_pull_request: - buildSummary += ' <tr>\n' - buildSummary += ' <td bgcolor="lightcyan" > <span class="glyphicon glyphicon-log-out"></span> Merge Request URL</td>\n' - buildSummary += ' <td><a href="TEMPLATE_MERGE_REQUEST_LINK">TEMPLATE_MERGE_REQUEST_LINK</a></td>\n' - buildSummary += ' </tr>\n' - buildSummary += ' <tr>\n' - buildSummary += ' <td bgcolor="lightcyan" > <span class="glyphicon glyphicon-header"></span> Merge Request Title</td>\n' - buildSummary += ' <td>TEMPLATE_MERGE_REQUEST_TEMPLATE</td>\n' - buildSummary += ' </tr>\n' - buildSummary += ' <tr>\n' - buildSummary += ' <td bgcolor="lightcyan" > <span class="glyphicon glyphicon-log-out"></span> Source Branch</td>\n' - buildSummary += ' <td>' + self.git_src_branch + '</td>\n' - buildSummary += ' </tr>\n' - buildSummary += ' <tr>\n' - buildSummary += ' <td bgcolor="lightcyan" > <span class="glyphicon glyphicon-tag"></span> Source Commit ID</td>\n' - buildSummary += ' <td>' + self.git_src_commit + '</td>\n' - buildSummary += ' </tr>\n' - if (self.git_src_commit_msg is not None): - buildSummary += ' <tr>\n' - buildSummary += ' <td bgcolor="lightcyan" > <span class="glyphicon glyphicon-comment"></span> Source Commit Message</td>\n' - buildSummary += ' <td>' + self.git_src_commit_msg + '</td>\n' - buildSummary += ' </tr>\n' - buildSummary += ' <tr>\n' - buildSummary += ' <td bgcolor="lightcyan" > <span class="glyphicon glyphicon-log-in"></span> Target Branch</td>\n' - buildSummary += ' <td>' + self.git_target_branch + '</td>\n' - buildSummary += ' </tr>\n' - buildSummary += ' <tr>\n' - buildSummary += ' <td bgcolor="lightcyan" > <span class="glyphicon glyphicon-tag"></span> Target Commit ID</td>\n' - buildSummary += ' <td>' + self.git_target_commit + '</td>\n' - buildSummary += ' </tr>\n' - else: - buildSummary += ' <tr>\n' - buildSummary += ' <td bgcolor="lightcyan" > <span class="glyphicon glyphicon-tree-deciduous"></span> Branch</td>\n' - buildSummary += ' <td>' + self.git_src_branch + '</td>\n' - buildSummary += ' </tr>\n' - buildSummary += ' <tr>\n' - buildSummary += ' <td bgcolor="lightcyan" > <span class="glyphicon glyphicon-tag"></span> Commit ID</td>\n' - buildSummary += ' <td>' + self.git_src_commit + '</td>\n' - buildSummary += ' </tr>\n' - if (self.git_src_commit_msg is not None): - buildSummary += ' <tr>\n' - buildSummary += ' <td bgcolor="lightcyan" > <span class="glyphicon glyphicon-comment"></span> Commit Message</td>\n' - buildSummary += ' <td>' + self.git_src_commit_msg + '</td>\n' - buildSummary += ' </tr>\n' - buildSummary += ' </table>\n' - buildSummary += ' <br>\n' - self.file.write(buildSummary) - - cwd = os.getcwd() - for reportFile in glob.glob('./*results_oai_*.html'): - if reportFile == './test_results_oai_pcf.html': - continue - newEpcReport = open(cwd + '/' + str(reportFile) + '.new', 'w') - buildSummaryDone = True - with open(cwd + '/' + str(reportFile), 'r') as originalEpcReport: - for line in originalEpcReport: - result = re.search('Deployment Summary', line) - if (result is not None) and buildSummaryDone: - newEpcReport.write(buildSummary) - buildSummaryDone = False - newEpcReport.write(line) - originalEpcReport.close() - newEpcReport.close() - os.rename(cwd + '/' + str(reportFile) + '.new', cwd + '/' + str(reportFile)) - - def generateFooter(self): - self.file.write(' <div class="well well-lg">End of Build Report -- Copyright <span class="glyphicon glyphicon-copyright-mark"></span> 2020 <a href="http://www.openairinterface.org/">OpenAirInterface</a>. All Rights Reserved.</div>\n') - self.file.write('</div></body>\n') - self.file.write('</html>\n') - - def coding_formatting_log(self): - cwd = os.getcwd() - self.file.write(' <h2>OAI Coding / Formatting Guidelines Check</h2>\n') - if os.path.isfile(cwd + '/src/oai_rules_result.txt'): - cmd = 'grep NB_FILES_FAILING_CHECK ' + cwd + '/src/oai_rules_result.txt | sed -e "s#NB_FILES_FAILING_CHECK=##"' - nb_fail = subprocess.check_output(cmd, shell=True, universal_newlines=True) - cmd = 'grep NB_FILES_CHECKED ' + cwd + '/src/oai_rules_result.txt | sed -e "s#NB_FILES_CHECKED=##"' - nb_total = subprocess.check_output(cmd, shell=True, universal_newlines=True) - if int(nb_fail.strip()) == 0: - self.file.write(' <div class="alert alert-success">\n') - if self.git_pull_request: - self.file.write(' <strong>All modified files in Pull-Request follow OAI rules. <span class="glyphicon glyphicon-ok-circle"></span> -> (' + nb_total.strip() + ' were checked)</strong>\n') - else: - self.file.write(' <strong>All files in repository follow OAI rules. <span class="glyphicon glyphicon-ok-circle"></span> -> (' + nb_total.strip() + ' were checked)</strong>\n') - self.file.write(' </div>\n') - else: - self.file.write(' <div class="alert alert-danger">\n') - if self.git_pull_request: - self.file.write(' <strong>' + nb_fail.strip() + ' modified files in Pull-Request DO NOT follow OAI rules. <span class="glyphicon glyphicon-warning-sign"></span> -> (' + nb_total.strip() + ' were checked)</strong>\n') - else: - self.file.write(' <strong>' + nb_fail.strip() + ' files in repository DO NOT follow OAI rules. <span class="glyphicon glyphicon-warning-sign"></span> -> (' + nb_total.strip() + ' were checked)</strong>\n') - self.file.write(' </div>\n') - - if os.path.isfile(cwd + '/src/oai_rules_result_list.txt'): - self.file.write(' <button data-toggle="collapse" data-target="#oai-formatting-details">More details on formatting check</button>\n') - self.file.write(' <div id="oai-formatting-details" class="collapse">\n') - self.file.write(' <p>Please apply the following command to this(ese) file(s): </p>\n') - self.file.write(' <p style="margin-left: 30px"><strong><code>cd src && clang-format -i filename(s)</code></strong></p>\n') - self.file.write(' <table class="table-bordered" width = "60%" align = "center" border = 1>\n') - self.file.write(' <tr><th bgcolor = "lightcyan" >Filename</th></tr>\n') - with open(cwd + '/src/oai_rules_result_list.txt', 'r') as filelist: - for line in filelist: - self.file.write(' <tr><td>' + line.strip() + '</td></tr>\n') - filelist.close() - self.file.write(' </table>\n') - self.file.write(' </div>\n') - else: - self.file.write(' <div class="alert alert-danger">\n') - self.file.write(' <strong>Was NOT performed (with CLANG-FORMAT tool). <span class="glyphicon glyphicon-ban-circle"></span></strong>\n') - self.file.write(' </div>\n') - - self.file.write(' <br>\n') - - def analyze_sca_log(self): - cwd = os.getcwd() - if os.path.isfile(cwd + '/archives/cppcheck_build.log'): - self.file.write(' <h2>Static Code Analysis</h2>\n') - if os.path.isfile(cwd + '/archives/cppcheck.xml'): - nb_errors = 0 - nb_warnings = 0 - nb_uninitvar = 0 - nb_uninitStructMember = 0 - nb_memleak = 0 - nb_doubleFree = 0 - nb_resourceLeak = 0 - nb_nullPointer = 0 - nb_arrayIndexOutOfBounds = 0 - nb_bufferAccessOutOfBounds = 0 - nb_unknownEvaluationOrder = 0 - with open(cwd + '/archives/cppcheck.xml', 'r') as xmlfile: - for line in xmlfile: - result = re.search('severity="warning"', line) - if result is not None: - nb_warnings += 1 - result = re.search('severity="error"', line) - if result is not None: - nb_errors += 1 - result = re.search('uninitvar', line) - if result is not None: - nb_uninitvar += 1 - result = re.search('uninitStructMember', line) - if result is not None: - nb_uninitStructMember += 1 - result = re.search('memleak', line) - if result is not None: - nb_memleak += 1 - result = re.search('doubleFree', line) - if result is not None: - nb_doubleFree += 1 - result = re.search('resourceLeak', line) - if result is not None: - nb_resourceLeak += 1 - result = re.search('nullPointer', line) - if result is not None: - nb_nullPointer += 1 - result = re.search('arrayIndexOutOfBounds', line) - if result is not None: - nb_arrayIndexOutOfBounds += 1 - result = re.search('bufferAccessOutOfBounds', line) - if result is not None: - nb_bufferAccessOutOfBounds += 1 - result = re.search('unknownEvaluationOrder', line) - if result is not None: - nb_unknownEvaluationOrder += 1 - xmlfile.close() - if (nb_errors == 0) and (nb_warnings == 0): - self.file.write(' <div class="alert alert-success">\n') - self.file.write(' <strong>CPPCHECK found NO error and NO warning <span class="glyphicon glyphicon-ok-circle"></span></strong>\n') - self.file.write(' </div>\n') - elif (nb_errors == 0): - self.file.write(' <div class="alert alert-warning">\n') - self.file.write(' <strong>CPPCHECK found NO error and ' + str(nb_warnings) + ' warnings <span class="glyphicon glyphicon-warning-sign"></span></strong>\n') - self.file.write(' </div>\n') - else: - self.file.write(' <div class="alert alert-danger">\n') - self.file.write(' <strong>CPPCHECK found ' + str(nb_errors) + ' errors and ' + str(nb_warnings) + ' warnings <span class="glyphicon glyphicon-ban-circle"></span></strong>\n') - self.file.write(' </div>\n') - if (nb_errors > 0) or (nb_warnings > 0): - self.file.write(' <button data-toggle="collapse" data-target="#oai-cppcheck-details">More details on CPPCHECK results</button>\n') - self.file.write(' <div id="oai-cppcheck-details" class="collapse">\n') - self.file.write(' <br>\n') - self.file.write(' <table class="table-bordered" width = "80%" align = "center" border = "1">\n') - self.file.write(' <tr bgcolor = "#33CCFF" >\n') - self.file.write(' <th>Error / Warning Type</th>\n') - self.file.write(' <th>Nb Errors</th>\n') - self.file.write(' <th>Nb Warnings</th>\n') - self.file.write(' </tr>\n') - self.file.write(' <tr>\n') - self.file.write(' <td>Uninitialized variable</td>\n') - self.file.write(' <td>' + str(nb_uninitvar) + '</td>\n') - self.file.write(' <td>N/A</td>\n') - self.file.write(' </tr>\n') - self.file.write(' <tr>\n') - self.file.write(' <td>Uninitialized struct member</td>\n') - self.file.write(' <td>' + str(nb_uninitStructMember) + '</td>\n') - self.file.write(' <td>N/A</td>\n') - self.file.write(' </tr>\n') - self.file.write(' <tr>\n') - self.file.write(' <td>Memory leak</td>\n') - self.file.write(' <td>' + str(nb_memleak) + '</td>\n') - self.file.write(' <td>N/A</td>\n') - self.file.write(' </tr>\n') - self.file.write(' <tr>\n') - self.file.write(' <td>Memory is freed twice</td>\n') - self.file.write(' <td>' + str(nb_doubleFree) + '</td>\n') - self.file.write(' <td>N/A</td>\n') - self.file.write(' </tr>\n') - self.file.write(' <tr>\n') - self.file.write(' <td>Resource leak</td>\n') - self.file.write(' <td>' + str(nb_resourceLeak) + '</td>\n') - self.file.write(' <td>N/A</td>\n') - self.file.write(' </tr>\n') - self.file.write(' <tr>\n') - self.file.write(' <td>Possible null pointer dereference</td>\n') - self.file.write(' <td>' + str(nb_nullPointer) + '</td>\n') - self.file.write(' <td>N/A</td>\n') - self.file.write(' </tr>\n') - self.file.write(' <tr>\n') - self.file.write(' <td>Array access out of bounds</td>\n') - self.file.write(' <td>' + str(nb_arrayIndexOutOfBounds) + '</td>\n') - self.file.write(' <td>N/A</td>\n') - self.file.write(' </tr>\n') - self.file.write(' <tr>\n') - self.file.write(' <td>Buffer is accessed out of bounds</td>\n') - self.file.write(' <td>' + str(nb_bufferAccessOutOfBounds) + '</td>\n') - self.file.write(' <td>N/A</td>\n') - self.file.write(' </tr>\n') - self.file.write(' <tr>\n') - self.file.write(' <td>Expression depends on order of evaluation of side effects</td>\n') - self.file.write(' <td>' + str(nb_unknownEvaluationOrder) + '</td>\n') - self.file.write(' <td>N/A</td>\n') - self.file.write(' </tr>\n') - self.file.write(' <tr>\n') - self.file.write(' <td>Others</td>\n') - nb_others = nb_uninitvar + nb_uninitStructMember + nb_memleak + nb_doubleFree + nb_resourceLeak + nb_nullPointer + nb_arrayIndexOutOfBounds + nb_arrayIndexOutOfBounds + nb_bufferAccessOutOfBounds + nb_unknownEvaluationOrder - nb_others = nb_errors - nb_others - self.file.write(' <td>' + str(nb_others) + '</td>\n') - self.file.write(' <td>' + str(nb_warnings) + '</td>\n') - self.file.write(' </tr>\n') - self.file.write(' <tr bgcolor = "#33CCFF" >\n') - self.file.write(' <th>Total</th>\n') - self.file.write(' <th>' + str(nb_errors) + '</th>\n') - self.file.write(' <th>' + str(nb_warnings) + '</th>\n') - self.file.write(' </tr>\n') - self.file.write(' </table>\n') - self.file.write(' <br>\n') - self.file.write(' <p>Full details in artifact (cppcheck.xml) </p>\n') - self.file.write(' <p style="margin-left: 30px">Graphical Interface tool : <strong><code>cppcheck-gui -l cppcheck.xml</code></strong></p>\n') - self.file.write(' <br>\n') - self.file.write(' </div>\n') - else: - self.file.write(' <div class="alert alert-danger">\n') - self.file.write(' <strong>Was NOT performed (with CPPCHECK tool). <span class="glyphicon glyphicon-ban-circle"></span></strong>\n') - self.file.write(' </div>\n') - - def buildSummaryHeader(self): - self.file.write(' <h2>Docker / Podman Image Build Summary</h2>\n') - self.file.write(' <table class="table-bordered" width = "100%" align = "center" border = "1">\n') - self.file.write(' <tr bgcolor="#33CCFF" >\n') - self.file.write(' <th>Stage Name</th>\n') - self.file.write(' <th>Image Kind</th>\n') - self.file.write(' <th>OAI PCF <font color="Gold">Ubuntu18</font> Image</th>\n') - self.file.write(' <th>OAI PCF <font color="Gold">RHEL8</font> Image</th>\n') - self.file.write(' </tr>\n') - - def buildSummaryFooter(self): - self.file.write(' </table>\n') - self.file.write(' <br>\n') - if self.nb_warnings > 0: - self.file.write(' <h3>Compilation Warnings Details</h3>\n') - self.file.write(' <button data-toggle="collapse" data-target="#oai-compilation-details">Details for Compilation Errors and Warnings </button>\n') - self.file.write(' <div id="oai-compilation-details" class="collapse">\n') - self.file.write(' <table class="table-bordered">\n') - self.file.write(' <tr bgcolor = "#33CCFF" >\n') - self.file.write(' <th>File</th>\n') - self.file.write(' <th>Line Number</th>\n') - self.file.write(' <th>Status</th>\n') - self.file.write(' <th>Message</th>\n') - self.file.write(self.warning_rows) - self.file.write(' </tr>\n') - self.file.write(' </table>\n') - self.file.write(' </div>\n') - - def initialGitSetup(self): - self.file.write(' <tr>\n') - self.file.write(' <td bgcolor="lightcyan" >Initial Git Setup</td>\n') - self.analyze_docker_build_git_part('PCF') - self.file.write(' </tr>\n') - - def analyze_docker_build_git_part(self, nfType): - if nfType != 'PCF': - self.file.write(' <td>N/A</td>\n') - self.file.write(' <td colspan="2">Wrong NF Type for this Report</td>\n') - return - - self.file.write(' <td>Builder Image</td>\n') - - cwd = os.getcwd() - variants = ['docker', 'podman'] - for variant in variants: - logFileName = 'pcf_' + variant + '_image_build.log' - if os.path.isfile(cwd + '/archives/' + logFileName): - status = False - section_start_pattern = 'git config --global http' - section_end_pattern = 'WORKDIR /openair-pcf/build/scripts' - section_status = False - with open(cwd + '/archives/' + logFileName, 'r') as logfile: - for line in logfile: - result = re.search(section_start_pattern, line) - if result is not None: - section_status = True - result = re.search(section_end_pattern, line) - if result is not None: - section_status = False - status = True - logfile.close() - - if status: - cell_msg = ' <td bgcolor="LimeGreen"><pre style="border:none; background-color:LimeGreen"><b>' - cell_msg += 'OK:\n' - cell_msg += ' -- All Git Operations went successfully</b></pre></td>\n' - else: - cell_msg = ' <td bgcolor="Tomato"><pre style="border:none; background-color:Tomato"><b>' - cell_msg += 'KO::\n' - cell_msg += ' -- Some Git Operations went WRONG</b></pre></td>\n' - else: - cell_msg = ' <td bgcolor="Tomato"><pre style="border:none; background-color:Tomato"><b>' - cell_msg += 'KO: logfile (' + logFileName + ') not found</b></pre></td>\n' - - self.file.write(cell_msg) - - def installLibsPackagesRow(self): - self.file.write(' <tr>\n') - self.file.write(' <td bgcolor="lightcyan" >SW libs and packages Installation</td>\n') - self.analyze_install_log('PCF') - self.file.write(' </tr>\n') - - def analyze_install_log(self, nfType): - if nfType != 'PCF': - self.file.write(' <td>N/A</td>\n') - self.file.write(' <td colspan="2">Wrong NF Type for this Report</td>\n') - return - - self.file.write(' <td>Builder Image</td>\n') - - cwd = os.getcwd() - variants = ['docker', 'podman'] - for variant in variants: - logFileName = 'pcf_' + variant + '_image_build.log' - if os.path.isfile(cwd + '/archives/' + logFileName): - status = False - section_start_pattern = 'build_pcf --install-deps --force' - section_end_pattern = 'build_pcf --clean --Verbose --build-type Release --jobs' - section_status = False - package_install = False - spdlog_build_start = False - spdlog_build_status = False - pistache_build_start = False - pistache_build_status = False - json_build_start = False - json_build_status = False - nghttp2_build_start = False - nghttp2_build_status = False - base_image = False - build_stage_id = 'NotAcorrectBuildStageId' - with open(cwd + '/archives/' + logFileName, 'r') as logfile: - for line in logfile: - # old method - result = re.search('FROM oai-pcf-base:latest', line) - if result is not None: - base_image = True - # new method --> buildx may cache this stage - result = re.search('^#([0-9]+).* RUN ./build_pcf --install-deps', line) - if result is not None: - build_stage_id = result.group(1) - result = re.search(f'^#{build_stage_id} CACHED', line) - if result is not None: - base_image = True - result = re.search(section_start_pattern, line) - if result is not None: - section_status = True - result = re.search(section_end_pattern, line) - if result is not None: - section_status = False - if section_status: - result = re.search('PCF deps installation successful', line) - if result is not None: - status = True - result = re.search('distro libs installation complete', line) - if result is not None: - package_install = True - result = re.search('Starting to install spdlog', line) - if result is not None: - spdlog_build_start = True - result = re.search('spdlog installation complete', line) - if result is not None and spdlog_build_start: - spdlog_build_status = True - result = re.search('Starting to install pistache', line) - if result is not None: - pistache_build_start = True - result = re.search('pistache installation complete', line) - if result is not None and pistache_build_start: - pistache_build_status = True - result = re.search('Starting to install Nlohmann Json', line) - if result is not None: - json_build_start = True - result = re.search('Nlohmann Json installation complete', line) - if result is not None and json_build_start: - json_build_status = True - result = re.search('Starting to install nghttp2', line) - if result is not None: - nghttp2_build_start = True - result = re.search('nghttp2 installation complete', line) - if result is not None and nghttp2_build_start: - nghttp2_build_status = True - logfile.close() - if base_image: - cell_msg = ' <td bgcolor="LimeGreen"><pre style="border:none; background-color:LimeGreen"><b>' - cell_msg += 'N/A:\n' - elif status: - cell_msg = ' <td bgcolor="LimeGreen"><pre style="border:none; background-color:LimeGreen"><b>' - cell_msg += 'OK:\n' - else: - cell_msg = ' <td bgcolor="Tomato"><pre style="border:none; background-color:Tomato"><b>' - cell_msg += 'KO:\n' - cell_msg += ' -- build_pcf --install-deps --force\n' - if base_image: - cell_msg += ' ** Packages Installation: N/A\n' - elif package_install: - cell_msg += ' ** Packages Installation: OK\n' - else: - cell_msg += ' ** Packages Installation: KO\n' - if base_image: - cell_msg += ' ** spdlog Installation: N/A\n' - elif spdlog_build_status: - cell_msg += ' ** spdlog Installation: OK\n' - else: - cell_msg += ' ** spdlog Installation: KO\n' - if base_image: - cell_msg += ' ** pistache Installation: N/A\n' - elif pistache_build_status: - cell_msg += ' ** pistache Installation: OK\n' - else: - cell_msg += ' ** pistache Installation: KO\n' - if base_image: - cell_msg += ' ** Nlohmann Json Installation: N/A\n' - elif json_build_status: - cell_msg += ' ** Nlohmann Json Installation: OK\n' - else: - cell_msg += ' ** Nlohmann Json Installation: KO\n' - if base_image: - cell_msg += ' ** nghttp2 Installation: N/A\n' - elif nghttp2_build_status: - cell_msg += ' ** nghttp2 Installation: OK\n' - else: - cell_msg += ' ** nghttp2 Installation: KO\n' - cell_msg += '</b></pre></td>\n' - else: - cell_msg = ' <td bgcolor="Tomato"><pre style="border:none; background-color:Tomato"><b>' - cell_msg += 'KO: logfile (' + logFileName + ') not found</b></pre></td>\n' - self.file.write(cell_msg) +from common.python.pipeline_args_parse import ( + _parse_args, +) - def buildCompileRows(self): - self.file.write(' <tr>\n') - self.file.write(' <td rowspan=2 bgcolor="lightcyan" >cNF Compile / Build</td>\n') - self.analyze_build_log('PCF', True) - self.file.write(' </tr>\n') - self.file.write(' <tr>\n') - self.analyze_compile_log('PCF', True) - self.file.write(' </tr>\n') +from common.python.generate_html import ( + generate_header, + generate_footer, + generate_git_info, +) - def analyze_build_log(self, nfType, imageKind): - if nfType != 'PCF': - if imageKind: - self.file.write(' <td>N/A</td>\n') - self.file.write(' <td colspan="2">Wrong NF Type for this Report</td>\n') - return +from common.python.code_format_checker import ( + coding_formatting_log_check, +) - if imageKind: - self.file.write(' <td>Builder Image</td>\n') +from common.python.static_code_analysis import ( + analyze_sca_log_check, +) - cwd = os.getcwd() - variants = ['docker', 'podman'] - for variant in variants: - logFileName = 'pcf_' + variant + '_image_build.log' - if os.path.isfile(cwd + '/archives/' + logFileName): - status = False - if nfType == 'PCF': - section_start_pattern = 'build_pcf --clean --Verbose --build-type Release --jobs' - section_end_pattern = 'FROM .* as oai-pcf$' - pass_pattern = 'pcf installed' - section_status = False - with open(cwd + '/archives/' + logFileName, 'r') as logfile: - for line in logfile: - result = re.search(section_start_pattern, line) - if result is not None: - section_status = True - result = re.search(section_end_pattern, line) - if result is not None: - section_status = False - if section_status: - result = re.search(pass_pattern, line) - if result is not None: - status = True - logfile.close() - if status: - cell_msg = ' <td bgcolor="LimeGreen"><pre style="border:none; background-color:LimeGreen"><b>' - cell_msg += 'OK:\n' - else: - cell_msg = ' <td bgcolor="Tomato"><pre style="border:none; background-color:Tomato"><b>' - cell_msg += 'KO:\n' - cell_msg += ' -- ' + section_start_pattern + '</b></pre></td>\n' - else: - cell_msg = ' <td bgcolor="Tomato"><pre style="border:none; background-color:Tomato"><b>' - cell_msg += 'KO: logfile (' + logFileName + ') not found</b></pre></td>\n' +from common.python.building_report import ( + build_summary, +) - self.file.write(cell_msg) +REPORT_NAME = 'test_results_oai_pcf.html' - def analyze_compile_log(self, nfType, imageKind): - if nfType != 'PCF': - if imageKind: - self.file.write(' <td>N/A</td>\n') - self.file.write(' <td colspan="2">Wrong NF Type for this Report</td>\n') - return - - if imageKind: - self.file.write(' <td>Builder Image</td>\n') - - cwd = os.getcwd() - variants = ['docker', 'podman'] - for variant in variants: - logFileName = 'pcf_' + variant + '_image_build.log' - nb_errors = 0 - nb_warnings = 0 - if os.path.isfile(cwd + '/archives/' + logFileName): - if nfType == 'PCF': - section_start_pattern = 'build_pcf --clean --Verbose --build-type Release --jobs' - section_end_pattern = 'FROM .* as oai-pcf$' - section_status = False - with open(cwd + '/archives/' + logFileName, 'r') as logfile: - for line in logfile: - result = re.search(section_start_pattern, line) - if result is not None: - section_status = True - result = re.search(section_end_pattern, line) - if result is not None: - section_status = False - if section_status: - result = re.search('error:', line) - if result is not None: - nb_errors += 1 - result = re.search('warning:', line) - if result is not None: - correctLine = re.sub("^.*/openair-pcf","/openair-pcf",line.strip()) - wordsList = correctLine.split(None,2) - filename = re.sub(":[0-9]*:[0-9]*:","", wordsList[0]) - linenumber = re.sub(filename + ':',"", wordsList[0]) - linenumber = re.sub(':[0-9]*:',"", linenumber) - error_warning_status = re.sub(':',"", wordsList[1]) - error_warning_msg = re.sub('^.*' + error_warning_status + ':', '', correctLine) - nb_warnings += 1 - self.warning_rows += '<tr><td>' + filename + '</td><td>' + linenumber + '</td><td>' + error_warning_status + '</td><td>' + error_warning_msg + '</td></tr>\n' - logfile.close() - if nb_warnings == 0 and nb_errors == 0: - cell_msg = ' <td bgcolor="LimeGreen"><pre style="border:none; background-color:LimeGreen"><b>' - elif nb_warnings < 20 and nb_errors == 0: - cell_msg = ' <td bgcolor="Orange"><pre style="border:none; background-color:Orange"><b>' - else: - cell_msg = ' <td bgcolor="Tomato"><pre style="border:none; background-color:Tomato"><b>' - if nb_errors > 0: - cell_msg += str(nb_errors) + ' errors found in compile log\n' - cell_msg += str(nb_warnings) + ' warnings found in compile log</b></pre></td>\n' - self.nb_warnings = nb_warnings - else: - cell_msg = ' <td bgcolor="Tomato"><pre style="border:none; background-color:Tomato"><b>' - cell_msg += 'KO: logfile (' + logFileName + ') not found</b></pre></td>\n' - - self.file.write(cell_msg) - - def copyToTargetImage(self): - self.file.write(' <tr>\n') - self.file.write(' <td bgcolor="lightcyan" >SW libs Installation / Copy from Builder</td>\n') - self.analyze_copy_log('PCF') - self.file.write(' </tr>\n') - - def analyze_copy_log(self, nfType): - if nfType != 'PCF': - self.file.write(' <td>N/A</td>\n') - self.file.write(' <td colspan="2">Wrong NF Type for this Report</td>\n') - return - - self.file.write(' <td>Target Image</td>\n') - - cwd = os.getcwd() - variants = ['docker', 'podman'] - for variant in variants: - logFileName = 'pcf_' + variant + '_image_build.log' - if os.path.isfile(cwd + '/archives/' + logFileName): - section_start_pattern = 'COPY --from=oai-pcf-builder */openair-pcf/build/pcf/build/oai_pcf' - section_end_pattern = 'COPY --from=oai-pcf-builder */openair-pcf/etc/pcf.conf ' - section_status = False - status = False - noPbInLDD = True - with open(cwd + '/archives/' + logFileName, 'r') as logfile: - for line in logfile: - result = re.search(section_start_pattern, line) - if result is not None: - section_status = True - result = re.search('not found', line) - if result is not None and section_status: - noPbInLDD = False - result = re.search(section_end_pattern, line) - if result is not None: - section_status = False - status = True - logfile.close() - if status and noPbInLDD: - cell_msg = ' <td bgcolor="LimeGreen"><pre style="border:none; background-color:LimeGreen"><b>' - cell_msg += 'OK:\n' - elif not noPbInLDD: - cell_msg = ' <td bgcolor="Tomato"><pre style="border:none; background-color:Tomato"><b>' - cell_msg += 'KO:\n' - cell_msg += ' Some libraries were not copied from builder image\n' - else: - cell_msg = ' <td bgcolor="Tomato"><pre style="border:none; background-color:Tomato"><b>' - cell_msg += 'KO:\n' - cell_msg += '</b></pre></td>\n' - else: - cell_msg = ' <td bgcolor="Tomato"><pre style="border:none; background-color:Tomato"><b>' - cell_msg += 'KO: logfile (' + logFileName + ') not found</b></pre></td>\n' - - self.file.write(cell_msg) - - def copyConfToolsToTargetImage(self): - self.file.write(' <tr>\n') - self.file.write(' <td bgcolor="lightcyan" >Copy Template Conf / Tools from Builder</td>\n') - self.analyze_copy_conf_tool_log('PCF') - self.file.write(' </tr>\n') - - def analyze_copy_conf_tool_log(self, nfType): - if nfType != 'PCF': - self.file.write(' <td>N/A</td>\n') - self.file.write(' <td colspan="2">Wrong NF Type for this Report</td>\n') - return - - self.file.write(' <td>Target Image</td>\n') - - cwd = os.getcwd() - variants = ['docker', 'podman'] - for variant in variants: - logFileName = 'pcf_' + variant + '_image_build.log' - if os.path.isfile(cwd + '/archives/' + logFileName): - section_start_pattern = 'WORKDIR /openair-pcf/etc' - if variant == 'docker': - section_end_pattern = 'naming to docker.io/library/oai-pcf:' - else: - section_end_pattern = 'COMMIT oai-pcf:' - section_status = False - status = False - with open(cwd + '/archives/' + logFileName, 'r') as logfile: - for line in logfile: - result = re.search(section_start_pattern, line) - if result is not None: - section_status = True - result = re.search(section_end_pattern, line) - if result is not None: - section_status = False - status = True - logfile.close() - if status: - cell_msg = ' <td bgcolor="LimeGreen"><pre style="border:none; background-color:LimeGreen"><b>' - cell_msg += 'OK:\n' - else: - cell_msg = ' <td bgcolor="Tomato"><pre style="border:none; background-color:Tomato"><b>' - cell_msg += 'KO:\n' - cell_msg += '</b></pre></td>\n' - else: - cell_msg = ' <td bgcolor="Tomato"><pre style="border:none; background-color:Tomato"><b>' - cell_msg += 'KO: logfile (' + logFileName + ') not found</b></pre></td>\n' - - self.file.write(cell_msg) - - def imageSizeRow(self): - self.file.write(' <tr>\n') - self.file.write(' <td bgcolor="lightcyan" >Image Size</td>\n') - self.analyze_image_size_log('PCF', True) - self.file.write(' </tr>\n') - - def analyze_image_size_log(self, nfType, imageKind): - if nfType != 'PCF': - if imageKind: - self.file.write(' <td>N/A</td>\n') - self.file.write(' <td colspan="2">Wrong NF Type for this Report</td>\n') - return - - if imageKind: - self.file.write(' <td>Target Image</td>\n') - - cwd = os.getcwd() - variants = ['docker', 'podman'] - for variant in variants: - logFileName = 'pcf_' + variant + '_image_build.log' - if os.path.isfile(cwd + '/archives/' + logFileName): - if nfType == 'PCF': - if variant == 'docker': - section_start_pattern = 'naming to docker.io/library/oai-pcf:' - section_end_pattern = 'OAI-PCF DOCKER IMAGE BUILD' - else: - section_start_pattern = 'COMMIT oai-pcf:' - section_end_pattern = 'OAI-PCF PODMAN RHEL8 IMAGE BUILD' - section_status = False - status = False - imageTag = 'notAcorrectTagForTheMoment' - with open(cwd + '/archives/' + logFileName, 'r') as logfile: - for line in logfile: - result = re.search(f'{section_start_pattern}([0-9a-zA-Z\-\_\.]+)', line) - if result is not None: - section_status = True - imageTag = result.group(1) - result = re.search(section_end_pattern, line) - if result is not None: - section_status = False - if section_status: - if nfType == 'PCF': - result = re.search(f'oai-pcf *{imageTag}', line) - if result is not None and not status: - result = re.search('ago *([0-9A-Z ]+)', line) - if result is not None: - size = result.group(1) - if variant == 'docker': - size = re.sub('MB', ' MB', size) - status = True - logfile.close() - if status: - cell_msg = ' <td bgcolor="LimeGreen"><pre style="border:none; background-color:LimeGreen"><b>' - cell_msg += 'OK: ' + size + '\n' - else: - cell_msg = ' <td bgcolor="Tomato"><pre style="border:none; background-color:Tomato"><b>' - cell_msg += 'KO:\n' - cell_msg += '</b></pre></td>\n' - else: - cell_msg = ' <td bgcolor="Tomato"><pre style="border:none; background-color:Tomato"><b>' - cell_msg += 'KO: logfile (' + logFileName + ') not found</b></pre></td>\n' - - self.file.write(cell_msg) - -def Usage(): - print('----------------------------------------------------------------------------------------------------------------------') - print('generateHtmlReport.py') - print(' Generate an HTML report for the Jenkins pipeline on openair-pcf.') - print('----------------------------------------------------------------------------------------------------------------------') - print('Usage: python3 generateHtmlReport.py [options]') - print(' --help Show this help.') - print('---------------------------------------------------------------------------------------------- Mandatory Options -----') - print(' --job_name=[Jenkins Job name]') - print(' --job_id=[Jenkins Job Build ID]') - print(' --job_url=[Jenkins Job Build URL]') - print(' --git_url=[Git Repository URL]') - print(' --git_src_branch=[Git Source Branch Name]') - print(' --git_src_commit=[Git Source Commit SHA-ONE]') - print('----------------------------------------------------------------------------------------------- Optional Options -----') - print(' --git_pull_request=True') - print(' --git_target_branch=[Git Target Branch Name]') - print(' --git_target_commit=[Git Target Commit SHA-ONE]') - -#-------------------------------------------------------------------------------------------------------- -# -# Start of main -# -#-------------------------------------------------------------------------------------------------------- - -argvs = sys.argv -argc = len(argvs) - -HTML = HtmlReport() - -while len(argvs) > 1: - myArgv = argvs.pop(1) - if re.match('^\-\-help$', myArgv, re.IGNORECASE): - Usage() - sys.exit(0) - elif re.match('^\-\-job_name=(.+)$', myArgv, re.IGNORECASE): - matchReg = re.match('^\-\-job_name=(.+)$', myArgv, re.IGNORECASE) - HTML.job_name = matchReg.group(1) - elif re.match('^\-\-job_id=(.+)$', myArgv, re.IGNORECASE): - matchReg = re.match('^\-\-job_id=(.+)$', myArgv, re.IGNORECASE) - HTML.job_id = matchReg.group(1) - elif re.match('^\-\-job_url=(.+)$', myArgv, re.IGNORECASE): - matchReg = re.match('^\-\-job_url=(.+)$', myArgv, re.IGNORECASE) - HTML.job_url = matchReg.group(1) - elif re.match('^\-\-git_url=(.+)$', myArgv, re.IGNORECASE): - matchReg = re.match('^\-\-git_url=(.+)$', myArgv, re.IGNORECASE) - HTML.git_url = matchReg.group(1) - elif re.match('^\-\-git_src_branch=(.+)$', myArgv, re.IGNORECASE): - matchReg = re.match('^\-\-git_src_branch=(.+)$', myArgv, re.IGNORECASE) - HTML.git_src_branch = matchReg.group(1) - elif re.match('^\-\-git_src_commit=(.+)$', myArgv, re.IGNORECASE): - matchReg = re.match('^\-\-git_src_commit=(.+)$', myArgv, re.IGNORECASE) - HTML.git_src_commit = matchReg.group(1) - elif re.match('^\-\-git_src_commit_msg=(.+)$', myArgv, re.IGNORECASE): - # Not Mandatory - matchReg = re.match('^\-\-git_src_commit_msg=(.+)$', myArgv, re.IGNORECASE) - HTML.git_src_commit_msg = matchReg.group(1) - elif re.match('^\-\-git_pull_request=(.+)$', myArgv, re.IGNORECASE): - # Can be silent: would be false! - matchReg = re.match('^\-\-git_pull_request=(.+)$', myArgv, re.IGNORECASE) - if matchReg.group(1) == 'true' or matchReg.group(1) == 'True': - HTML.git_pull_request = True - elif re.match('^\-\-git_target_branch=(.+)$', myArgv, re.IGNORECASE): - matchReg = re.match('^\-\-git_target_branch=(.+)$', myArgv, re.IGNORECASE) - HTML.git_target_branch = matchReg.group(1) - elif re.match('^\-\-git_target_commit=(.+)$', myArgv, re.IGNORECASE): - matchReg = re.match('^\-\-git_target_commit=(.+)$', myArgv, re.IGNORECASE) - HTML.git_target_commit = matchReg.group(1) - else: - sys.exit('Invalid Parameter: ' + myArgv) - -if HTML.job_name == '' or HTML.job_id == '' or HTML.job_url == '': - sys.exit('Missing Parameter in job description') - -if HTML.git_url == '' or HTML.git_src_branch == '' or HTML.git_src_commit == '': - sys.exit('Missing Parameter in Git Repository description') - -if HTML.git_pull_request: - if HTML.git_target_commit == '' or HTML.git_target_branch == '': - sys.exit('Missing Parameter in Git Pull Request Repository description') - -HTML.generate() +class HtmlReport(): + def __init__(self): + pass + + def generate(self, args): + cwd = os.getcwd() + with open(os.path.join(cwd, REPORT_NAME), 'w') as wfile: + wfile.write(generate_header(args)) + wfile.write(generate_git_info(args)) + wfile.write(build_summary(args, 'pcf', '20', '8')) + wfile.write(coding_formatting_log_check(args)) + wfile.write(analyze_sca_log_check()) + wfile.write(generate_footer()) + + def appendToTestReports(self, args): + gitInfo = generate_git_info(args) + cwd = os.getcwd() + for reportFile in os.listdir(cwd): + if reportFile.endswith('.html') and re.search('results_oai_cn5g_', reportFile) is not None: + newFile = '' + gitInfoAppended = False + with open(os.path.join(cwd, reportFile), 'r') as rfile: + for line in rfile: + if re.search('<h2>', line) is not None and not gitInfoAppended: + gitInfoAppended = True + newFile += gitInfo + newFile += line + with open(os.path.join(cwd, reportFile), 'w') as wfile: + wfile.write(newFile) + +if __name__ == '__main__': + # Parse the arguments + args = _parse_args() + + # Generate report + HTML = HtmlReport() + HTML.generate(args) + HTML.appendToTestReports(args) diff --git a/ci-scripts/openshift/oai-pcf-bc.yaml b/ci-scripts/openshift/oai-pcf-bc.yaml deleted file mode 100644 index e13dbf6705fd85cf09e5a3a32ffbcdd9edae018c..0000000000000000000000000000000000000000 --- a/ci-scripts/openshift/oai-pcf-bc.yaml +++ /dev/null @@ -1,50 +0,0 @@ -#/* -# * Licensed to the OpenAirInterface (OAI) Software Alliance under one or more -# * contributor license agreements. See the NOTICE file distributed with -# * this work for additional information regarding copyright ownership. -# * The OpenAirInterface Software Alliance licenses this file to You under -# * the OAI Public License, Version 1.1 (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.openairinterface.org/?page_id=698 -# * -# * 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. -# *------------------------------------------------------------------------------- -# * For more information about the OpenAirInterface (OAI) Software Alliance: -# * contact@openairinterface.org -# */ -#--------------------------------------------------------------------- -# ---- -kind: BuildConfig -apiVersion: build.openshift.io/v1 -metadata: - name: "oai-pcf" - namespace: oaicicd-core -spec: - runPolicy: "Serial" - source: - type: "Binary" - secrets: - - secret: - name: etc-pki-entitlement - destinationDir: etc-pki-entitlement - configMaps: - - configMap: - name: rhsm-conf - destinationDir: rhsm-conf - - configMap: - name: rhsm-ca - destinationDir: rhsm-ca - strategy: - dockerStrategy: - dockerfilePath: "docker/Dockerfile.pcf.rhel8" - output: - to: - kind: "ImageStreamTag" - name: "oai-pcf:develop" diff --git a/ci-scripts/openshift/oai-pcf-is.yaml b/ci-scripts/openshift/oai-pcf-is.yaml deleted file mode 100644 index d6465da9c3afe775d1fa1d0072b80a4399daff97..0000000000000000000000000000000000000000 --- a/ci-scripts/openshift/oai-pcf-is.yaml +++ /dev/null @@ -1,32 +0,0 @@ -#/* -# * Licensed to the OpenAirInterface (OAI) Software Alliance under one or more -# * contributor license agreements. See the NOTICE file distributed with -# * this work for additional information regarding copyright ownership. -# * The OpenAirInterface Software Alliance licenses this file to You under -# * the OAI Public License, Version 1.1 (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.openairinterface.org/?page_id=698 -# * -# * 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. -# *------------------------------------------------------------------------------- -# * For more information about the OpenAirInterface (OAI) Software Alliance: -# * contact@openairinterface.org -# */ -#--------------------------------------------------------------------- -# -apiVersion: image.openshift.io/v1 -kind: ImageStream -metadata: - name: oai-pcf - namespace: oaicicd-core -spec: - lookupPolicy: - local: true -status: - tag: develop diff --git a/docker/Dockerfile.pcf.rhel8 b/docker/Dockerfile.pcf.rhel8 index f1342ff9d89d0ce0d513497bba4be78756989de8..915e6511aed219a5aa1b67753e6615309f33c9ab 100644 --- a/docker/Dockerfile.pcf.rhel8 +++ b/docker/Dockerfile.pcf.rhel8 @@ -122,9 +122,7 @@ COPY --from=oai-pcf-builder \ /usr/local/lib/libnghttp2_asio.so.1 \ /usr/local/lib64/libspdlog.so \ /usr/local/lib64/libfmt.so \ -# libyaml-cpp is installed via epel-8 -# and epel-8 cannot be installed on ubi-minimal - /lib64/libyaml-cpp.so.0.6 \ + /usr/local/lib64/libyaml-cpp.so.0.* \ /usr/lib64/ RUN ldconfig && \ diff --git a/docker/Dockerfile.pcf.ubuntu b/docker/Dockerfile.pcf.ubuntu index 03a6fc02b35fc58a443edbff96471d12db4f8f64..245787b77b1681091abc6f4b0887dfb39ef605ef 100644 --- a/docker/Dockerfile.pcf.ubuntu +++ b/docker/Dockerfile.pcf.ubuntu @@ -31,7 +31,7 @@ #--------------------------------------------------------------------- # BASE IMAGE #--------------------------------------------------------------------- -ARG BASE_IMAGE=ubuntu:bionic +ARG BASE_IMAGE=ubuntu:focal FROM $BASE_IMAGE as oai-pcf-base ENV DEBIAN_FRONTEND=noninteractive @@ -51,7 +51,7 @@ RUN git config --global https.postBuffer 123289600 && \ # Copying source code WORKDIR /openair-pcf COPY ./build/scripts /openair-pcf/build/scripts/ -COPY ./build/build-common /openair-pcf/build/build-common/ +COPY ./build/common-build /openair-pcf/build/common-build/ COPY ./build/pcf/CMakeLists.txt /openair-pcf/build/pcf/CMakeLists.txt COPY ./build/cmake_modules /openair-pcf/build/cmake_modules/ @@ -100,10 +100,6 @@ RUN apt-get update && \ libcurl?-gnutls \ librtmp1 \ libpsl5 \ -# Ubuntu 18 --> won't install anything -# Ubuntu 20 --> libyaml-cpp 0.6 -# Ubuntu 22 --> libyaml-cpp 0.7 - libyaml-cpp0.? \ && rm -rf /var/lib/apt/lists/* \ /lib/x86_64-linux-gnu/libboost_system.so.1.6*.0 \ /lib/x86_64-linux-gnu/ibboost_filesystem.so.1.6*.0 diff --git a/src/api-server/CMakeLists.txt b/src/api-server/CMakeLists.txt index cb8a4aa7a36fd2a8c3a0d1cd8e750d5ac0e8744b..29e978bc08e7b3b36407a2bbf2eae75c083d2c55 100644 --- a/src/api-server/CMakeLists.txt +++ b/src/api-server/CMakeLists.txt @@ -24,6 +24,7 @@ set(PCF_API_SERVER_DIR "${SRC_TOP_DIR}/api-server") include_directories(${PCF_API_SERVER_DIR}/api) include_directories(${PCF_API_SERVER_DIR}/impl) include_directories(${PCF_API_SERVER_DIR}/model) +include_directories(${PCF_API_SERVER_DIR}/handler) include_directories(${PCF_API_SERVER_DIR}/) include_directories(${SRC_TOP_DIR}/pcf_app) include_directories(${SRC_TOP_DIR}/common) @@ -34,9 +35,11 @@ include_directories(${SRC_TOP_DIR}/${MOUNTED_COMMON}/config) file(GLOB PCF_API_SERVER_src_files ${PCF_API_SERVER_DIR}/pcf-api-server.cpp ${PCF_API_SERVER_DIR}/pcf-http2-server.cpp + ${PCF_API_SERVER_DIR}/api_defs.cpp ${PCF_API_SERVER_DIR}/model/*.cpp ${PCF_API_SERVER_DIR}/api/*.cpp ${PCF_API_SERVER_DIR}/impl/*.cpp + ${PCF_API_SERVER_DIR}/handler/*.cpp ) add_library(PCF_API STATIC diff --git a/src/api-server/api/IndividualSMPolicyDocumentApi.cpp b/src/api-server/api/IndividualSMPolicyDocumentApi.cpp index aec7bf6dcf5d8e2a336bebbc5d5f9d7f58014789..87d3d4a5a7d36db47dc214d95e336c863a2abc43 100644 --- a/src/api-server/api/IndividualSMPolicyDocumentApi.cpp +++ b/src/api-server/api/IndividualSMPolicyDocumentApi.cpp @@ -13,17 +13,14 @@ #include "IndividualSMPolicyDocumentApi.h" #include "Helpers.h" +#include "api_defs.h" +#include "pcf_config.hpp" -namespace oai { -namespace pcf { -namespace api { +namespace oai::pcf::api { using namespace oai::model::common::helpers; using namespace oai::pcf::model; -const std::string IndividualSMPolicyDocumentApi::base = - "/npcf-smpolicycontrol/v1"; - IndividualSMPolicyDocumentApi::IndividualSMPolicyDocumentApi( const std::shared_ptr<Pistache::Rest::Router>& rtr) : router(rtr) {} @@ -34,17 +31,16 @@ void IndividualSMPolicyDocumentApi::init() { void IndividualSMPolicyDocumentApi::setupRoutes() { using namespace Pistache::Rest; - Routes::Post( - *router, base + "/sm-policies/:smPolicyId/delete", + *router, sm_policies::get_route() + "/:smPolicyId/delete", Routes::bind( &IndividualSMPolicyDocumentApi::delete_sm_policy_handler, this)); Routes::Get( - *router, base + "/sm-policies/:smPolicyId", + *router, sm_policies::get_route() + "/:smPolicyId", Routes::bind( &IndividualSMPolicyDocumentApi::get_sm_policy_handler, this)); Routes::Post( - *router, base + "/sm-policies/:smPolicyId/update", + *router, sm_policies::get_route() + "/:smPolicyId/update", Routes::bind( &IndividualSMPolicyDocumentApi::update_sm_policy_handler, this)); @@ -183,6 +179,4 @@ void IndividualSMPolicyDocumentApi:: Pistache::Http::Code::Not_Found, "The requested method does not exist"); } -} // namespace api -} // namespace pcf -} // namespace oai +} // namespace oai::pcf::api diff --git a/src/api-server/api/IndividualSMPolicyDocumentApi.h b/src/api-server/api/IndividualSMPolicyDocumentApi.h old mode 100755 new mode 100644 index fde978c08596ccdaf5cce4614534f85120260f09..8c85924d0b4490cced1a87c5a22045b4e2b9272c --- a/src/api-server/api/IndividualSMPolicyDocumentApi.h +++ b/src/api-server/api/IndividualSMPolicyDocumentApi.h @@ -33,9 +33,7 @@ #include "SmPolicyUpdateContextData.h" #include <string> -namespace oai { -namespace pcf { -namespace api { +namespace oai::pcf::api { using namespace oai::pcf::model; @@ -46,8 +44,6 @@ class IndividualSMPolicyDocumentApi { virtual ~IndividualSMPolicyDocumentApi() = default; void init(); - static const std::string base; - private: void setupRoutes(); @@ -121,8 +117,6 @@ class IndividualSMPolicyDocumentApi { Pistache::Http::ResponseWriter& response) = 0; }; -} // namespace api -} // namespace pcf -} // namespace oai +} // namespace oai::pcf::api #endif /* IndividualSMPolicyDocumentApi_H_ */ diff --git a/src/api-server/api/SMPoliciesCollectionApi.cpp b/src/api-server/api/SMPoliciesCollectionApi.cpp index f4c39fbcfe1b146154f068e4cc5ddd137bb32f8d..a72272587e664362d7cb7770db34e9b1166e68ea 100644 --- a/src/api-server/api/SMPoliciesCollectionApi.cpp +++ b/src/api-server/api/SMPoliciesCollectionApi.cpp @@ -12,6 +12,8 @@ */ #include "SMPoliciesCollectionApi.h" +#include "api_defs.h" +#include "pcf_config.hpp" namespace oai { namespace pcf { @@ -20,8 +22,6 @@ namespace api { using namespace oai::model::common::helpers; using namespace oai::pcf::model; -const std::string SMPoliciesCollectionApi::base = "/npcf-smpolicycontrol/v1"; - SMPoliciesCollectionApi::SMPoliciesCollectionApi( const std::shared_ptr<Pistache::Rest::Router>& rtr) : router(rtr) {} @@ -34,7 +34,7 @@ void SMPoliciesCollectionApi::setupRoutes() { using namespace Pistache::Rest; Routes::Post( - *router, base + "/sm-policies", + *router, sm_policies::get_route(), Routes::bind(&SMPoliciesCollectionApi::create_sm_policy_handler, this)); // Default handler, called when a route is not found diff --git a/src/api-server/api/SMPoliciesCollectionApi.h b/src/api-server/api/SMPoliciesCollectionApi.h index b59d17953a81d6e5e64de62ab6fe202d9c11a80e..49c79e0218e8aab38c75b7487e4c37b16f1970b9 100755 --- a/src/api-server/api/SMPoliciesCollectionApi.h +++ b/src/api-server/api/SMPoliciesCollectionApi.h @@ -46,8 +46,6 @@ class SMPoliciesCollectionApi { virtual ~SMPoliciesCollectionApi() = default; void init(); - static const std::string base; - private: void setupRoutes(); diff --git a/src/api-server/api_defs.cpp b/src/api-server/api_defs.cpp new file mode 100644 index 0000000000000000000000000000000000000000..84e1a517dc893042912e884a23c0ad7b5aacbfcf --- /dev/null +++ b/src/api-server/api_defs.cpp @@ -0,0 +1,42 @@ +/* + * Licensed to the OpenAirInterface (OAI) Software Alliance under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The OpenAirInterface Software Alliance licenses this file to You under + * the OAI Public License, Version 1.1 (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.openairinterface.org/?page_id=698 + * + * 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. + *------------------------------------------------------------------------------- + * For more information about the OpenAirInterface (OAI) Software Alliance: + * contact@openairinterface.org + */ + +/*! \file api_defs.h + \brief + \author Stefan Spettel + \company phine.tech + \date 2023 + \email: stefan.spettel@phine.tech + */ + +#include "api_defs.h" + +#include "pcf_config.hpp" + +extern std::unique_ptr<oai::pcf::config::pcf_config> pcf_cfg; + +namespace oai::pcf::api { + +std::string sm_policies::get_route() { + return API_BASE + pcf_cfg->sbi.get_api_version() + sm_policies::CREATE_ROUTE; +} + +} // namespace oai::pcf::api diff --git a/src/api-server/api_defs.h b/src/api-server/api_defs.h new file mode 100644 index 0000000000000000000000000000000000000000..72858e5615e2bb3c14cc5f83a9df6896f635d431 --- /dev/null +++ b/src/api-server/api_defs.h @@ -0,0 +1,43 @@ +/* + * Licensed to the OpenAirInterface (OAI) Software Alliance under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The OpenAirInterface Software Alliance licenses this file to You under + * the OAI Public License, Version 1.1 (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.openairinterface.org/?page_id=698 + * + * 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. + *------------------------------------------------------------------------------- + * For more information about the OpenAirInterface (OAI) Software Alliance: + * contact@openairinterface.org + */ + +/*! \file api_defs.h + \brief + \author Stefan Spettel + \company phine.tech + \date 2023 + \email: stefan.spettel@phine.tech + */ + +#pragma once +#include <string> + +namespace oai::pcf::api { +class sm_policies { + public: + static inline const std::string API_NAME = "npcf-smpolicycontrol"; + static inline const std::string API_BASE = "/" + API_NAME + "/"; + static inline const std::string CREATE_ROUTE = "/sm-policies"; + + static std::string get_route(); +}; + +} // namespace oai::pcf::api \ No newline at end of file diff --git a/src/api-server/handler/api_response.h b/src/api-server/handler/api_response.h new file mode 100644 index 0000000000000000000000000000000000000000..3a5597ef7d38e186248404b12ee5004b34589a53 --- /dev/null +++ b/src/api-server/handler/api_response.h @@ -0,0 +1,45 @@ + +/* + * Licensed to the OpenAirInterface (OAI) Software Alliance under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The OpenAirInterface Software Alliance licenses this file to You under + * the OAI Public License, Version 1.1 (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.openairinterface.org/?page_id=698 + * + * 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. + *------------------------------------------------------------------------------- + * For more information about the OpenAirInterface (OAI) Software Alliance: + * contact@openairinterface.org + */ + +/*! \file sm_policies_collection_api_handler.cpp + \brief + \author Stefan Spettel + \company phine.tech + \date 2023 + \email: stefan.spettel@phine.tech + */ + +#pragma once + +#include "3gpp_29.500.h" + +#include <pistache/http_headers.h> + +namespace oai::pcf::api { + +struct api_response { + http_status_code_e status_code; + Pistache::Http::Header::Collection headers; + std::string body; +}; + +} // namespace oai::pcf::api \ No newline at end of file diff --git a/src/api-server/handler/individual_sm_policy_document_api_handler.cpp b/src/api-server/handler/individual_sm_policy_document_api_handler.cpp new file mode 100644 index 0000000000000000000000000000000000000000..2a7cbfb3383882a3f5754851f5b60eb29bd18a58 --- /dev/null +++ b/src/api-server/handler/individual_sm_policy_document_api_handler.cpp @@ -0,0 +1,183 @@ +/* + * Licensed to the OpenAirInterface (OAI) Software Alliance under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The OpenAirInterface Software Alliance licenses this file to You under + * the OAI Public License, Version 1.1 (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.openairinterface.org/?page_id=698 + * + * 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. + *------------------------------------------------------------------------------- + * For more information about the OpenAirInterface (OAI) Software Alliance: + * contact@openairinterface.org + */ + +/*! \file individual_sm_policy_document_api_handler.cpp + \brief + \author Stefan Spettel + \company phine.tech + \date 2023 + \email: stefan.spettel@phine.tech + */ + +#include "individual_sm_policy_document_api_handler.h" +#include "ProblemDetails.h" + +namespace oai::pcf::api { + +using namespace oai::pcf::model; +using namespace oai::model::common; +using namespace oai::pcf::app::sm_policy; + +api_response individual_sm_policy_document_api_handler::delete_sm_policy( + const std::string& sm_policy_id, + const SmPolicyDeleteData& sm_policy_delete_data) { + api_response response; + + ProblemDetails problem_details; + std::string problem_description; + std::string content_type = "application/problem+json"; + nlohmann::json json_data; + http_status_code_e http_code; + status_code res = m_smpc_service->delete_sm_policy_handler( + sm_policy_id, sm_policy_delete_data, problem_description); + + switch (res) { + case status_code::OK: + http_code = http_status_code_e::HTTP_STATUS_CODE_204_NO_CONTENT; + break; + + case status_code::NOT_FOUND: + problem_details.setDetail(problem_description); + // This is not defined in the standard + problem_details.setCause("SM_POLICY_ID_NOT_FOUND"); + http_code = http_status_code_e::HTTP_STATUS_CODE_404_NOT_FOUND; + break; + + default: + problem_details.setDetail("Internal Service Error: Unknown return code."); + problem_details.setCause("INTERNAL_ERROR"); + http_code = + http_status_code_e::HTTP_STATUS_CODE_500_INTERNAL_SERVER_ERROR; + } + response.status_code = http_code; + if (res != status_code::OK) { + response.headers.add<Pistache::Http::Header::ContentType>( + Pistache::Http::Mime::MediaType(content_type)); + to_json(json_data, problem_details); + response.body = json_data.dump(); + } + return response; +} + +api_response individual_sm_policy_document_api_handler::get_sm_policy( + const std::string& sm_policy_id) { + api_response response; + ProblemDetails problem_details; + std::string problem_description; + std::string content_type = "application/problem+json"; + nlohmann::json json_data; + http_status_code_e http_code; + + SmPolicyControl sm_policy_control; + + status_code res = m_smpc_service->get_sm_policy_handler( + sm_policy_id, sm_policy_control, problem_description); + + switch (res) { + case status_code::OK: + http_code = http_status_code_e::HTTP_STATUS_CODE_200_OK; + content_type = "application/json"; + break; + + case status_code::NOT_FOUND: + problem_details.setDetail(problem_description); + // This is not defined in the standard + problem_details.setCause("SM_POLICY_ID_NOT_FOUND"); + http_code = http_status_code_e::HTTP_STATUS_CODE_404_NOT_FOUND; + break; + + default: + problem_details.setDetail("Internal Service Error: Unknown return code."); + problem_details.setCause("INTERNAL_ERROR"); + http_code = + http_status_code_e::HTTP_STATUS_CODE_500_INTERNAL_SERVER_ERROR; + } + + if (res == status_code::OK) { + to_json(json_data, sm_policy_control); + } else { + to_json(json_data, problem_details); + } + response.status_code = http_code; + response.body = json_data.dump(); + response.headers.add<Pistache::Http::Header::ContentType>( + Pistache::Http::Mime::MediaType(content_type)); + + return response; +} + +api_response individual_sm_policy_document_api_handler::update_sm_policy( + const std::string& sm_policy_id, + const SmPolicyUpdateContextData& sm_policy_update_context_data) { + api_response response; + ProblemDetails problem_details; + std::string problem_description; + std::string content_type = "application/problem+json"; + nlohmann::json json_data; + http_status_code_e http_code; + + SmPolicyDecision decision_update; + + status_code res = m_smpc_service->update_sm_policy_handler( + sm_policy_id, sm_policy_update_context_data, decision_update, + problem_description); + + problem_details.setDetail(problem_description); + + switch (res) { + case status_code::OK: + content_type = "application/json"; + http_code = http_status_code_e::HTTP_STATUS_CODE_200_OK; + break; + case status_code::INVALID_PARAMETERS: + http_code = http_status_code_e::HTTP_STATUS_CODE_400_BAD_REQUEST; + problem_details.setCause("ERROR_INITIAL_PARAMETERS"); + break; + case status_code::CONTEXT_DENIED: + // should map to 403 but not defined in standard for this request + http_code = http_status_code_e::HTTP_STATUS_CODE_400_BAD_REQUEST; + problem_details.setCause("ERROR_INITIAL_PARAMETERS"); + break; + case status_code::NOT_FOUND: + // TODO This is not defined in the standard, but this scenario is missing + // we could map it to the 400 Bad request but that is somehow misleading + problem_details.setCause("SM_POLICY_ID_NOT_FOUND"); + http_code = http_status_code_e::HTTP_STATUS_CODE_404_NOT_FOUND; + break; + default: + problem_details.setCause("INTERNAL_ERROR"); + http_code = + http_status_code_e::HTTP_STATUS_CODE_500_INTERNAL_SERVER_ERROR; + } + + if (res == status_code::OK) { + to_json(json_data, decision_update); + } else { + to_json(json_data, problem_details); + } + + response.headers.add<Pistache::Http::Header::ContentType>( + Pistache::Http::Mime::MediaType(content_type)); + response.body = json_data.dump(); + response.status_code = http_code; + return response; +} +} // namespace oai::pcf::api diff --git a/src/api-server/handler/individual_sm_policy_document_api_handler.h b/src/api-server/handler/individual_sm_policy_document_api_handler.h new file mode 100644 index 0000000000000000000000000000000000000000..644f8b069dd6063eb02a389a294cbad41aec1a37 --- /dev/null +++ b/src/api-server/handler/individual_sm_policy_document_api_handler.h @@ -0,0 +1,79 @@ + +/* + * Licensed to the OpenAirInterface (OAI) Software Alliance under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The OpenAirInterface Software Alliance licenses this file to You under + * the OAI Public License, Version 1.1 (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.openairinterface.org/?page_id=698 + * + * 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. + *------------------------------------------------------------------------------- + * For more information about the OpenAirInterface (OAI) Software Alliance: + * contact@openairinterface.org + */ + +/*! \file individual_sm_policy_document_api_handler.cpp + \brief + \author Stefan Spettel + \company phine.tech + \date 2023 + \email: stefan.spettel@phine.tech + */ + +#pragma once + +#include "3gpp_29.500.h" +#include "api_response.h" +#include "pcf_sm_policy_control.hpp" +#include "SmPolicyDeleteData.h" +#include "SmPolicyUpdateContextData.h" + +namespace oai::pcf::api { + +class individual_sm_policy_document_api_handler { + public: + explicit individual_sm_policy_document_api_handler( + const std::shared_ptr<oai::pcf::app::pcf_smpc>& pcf_smpc) { + m_smpc_service = pcf_smpc; + } + /** + * Delete SM Policy based on ID + * @param sm_policy_id + * @param sm_policy_delete_data + * @return api_response + */ + api_response delete_sm_policy( + const std::string& sm_policy_id, + const oai::pcf::model::SmPolicyDeleteData& sm_policy_delete_data); + + /** + * Get SM Policy by ID + * @param sm_policy_id + * @return api_response + */ + api_response get_sm_policy(const std::string& sm_policy_id); + + /** + * Update SM Policy by ID and mandatory update context data + * @param sm_policy_id + * @param smPolicyUpdateContextData + * @return + */ + api_response update_sm_policy( + const std::string& sm_policy_id, + const oai::pcf::model::SmPolicyUpdateContextData& + smPolicyUpdateContextData); + + private: + std::shared_ptr<oai::pcf::app::pcf_smpc> m_smpc_service; +}; + +} // namespace oai::pcf::api \ No newline at end of file diff --git a/src/api-server/handler/sm_policies_collection_api_handler.cpp b/src/api-server/handler/sm_policies_collection_api_handler.cpp new file mode 100644 index 0000000000000000000000000000000000000000..b212d1ecc5f561984dcfef0b90ff0523174aab6d --- /dev/null +++ b/src/api-server/handler/sm_policies_collection_api_handler.cpp @@ -0,0 +1,108 @@ +/* + * Licensed to the OpenAirInterface (OAI) Software Alliance under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The OpenAirInterface Software Alliance licenses this file to You under + * the OAI Public License, Version 1.1 (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.openairinterface.org/?page_id=698 + * + * 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. + *------------------------------------------------------------------------------- + * For more information about the OpenAirInterface (OAI) Software Alliance: + * contact@openairinterface.org + */ + +/*! \file sm_policies_collection_api_handler.cpp + \brief + \author Stefan Spettel + \company phine.tech + \date 2023 + \email: stefan.spettel@phine.tech + */ + +#include "api_response.h" +#include "sm_policies_collection_api_handler.h" + +#include "ProblemDetails.h" +#include "SmPolicyDecision.h" +#include "SMPoliciesCollectionApi.h" +#include "logger.hpp" +#include "api_defs.h" +#include "pcf_config.hpp" + +namespace oai::pcf::api { + +using namespace oai::pcf::model; +using namespace oai::model::common; +using namespace oai::pcf::app::sm_policy; + +api_response sm_policies_collection_api_handler::create_sm_policy( + const SmPolicyContextData& sm_policy_context_data) { + http_status_code_e http_code; + std::string cause; + ProblemDetails problem_details; + SmPolicyDecision decision; + std::string details_string; + std::string association_id; + std::string location; + std::string content_type = "application/problem+json"; + api_response response; + + status_code res = m_smpc_service->create_sm_policy_handler( + sm_policy_context_data, decision, association_id, details_string); + nlohmann::json json_data; + + switch (res) { + case status_code::CREATED: + http_code = http_status_code_e::HTTP_STATUS_CODE_201_CREATED; + location = m_address + sm_policies::get_route() + "/" + association_id; + content_type = "application/json"; + break; + + case status_code::USER_UNKOWN: + problem_details.setCause("USER_UNKOWN"); + problem_details.setDetail(details_string); + http_code = http_status_code_e::HTTP_STATUS_CODE_400_BAD_REQUEST; + break; + + case status_code::INVALID_PARAMETERS: + problem_details.setCause("ERROR_INITIAL_PARAMETERS"); + problem_details.setDetail(details_string); + http_code = http_status_code_e::HTTP_STATUS_CODE_400_BAD_REQUEST; + break; + + case status_code::CONTEXT_DENIED: + problem_details.setCause("POLICY_CONTEXT_DENIED"); + problem_details.setDetail(details_string); + http_code = http_status_code_e::HTTP_STATUS_CODE_403_FORBIDDEN; + break; + + default: + Logger::pcf_app().error("Unknown error code"); + http_code = + http_status_code_e::HTTP_STATUS_CODE_500_INTERNAL_SERVER_ERROR; + problem_details.setCause("INTERNAL_ERROR"); + problem_details.setDetail("Internal Service Error: Unknown return code."); + } + + if (http_code != http_status_code_e::HTTP_STATUS_CODE_201_CREATED) { + to_json(json_data, problem_details); + } else { + to_json(json_data, decision); + response.headers.add<Pistache::Http::Header::Location>(location); + } + response.headers.add<Pistache::Http::Header::ContentType>( + Pistache::Http::Mime::MediaType(content_type)); + response.body = json_data.dump(); + response.status_code = http_code; + return response; +} + +} // namespace oai::pcf::api diff --git a/src/api-server/handler/sm_policies_collection_api_handler.h b/src/api-server/handler/sm_policies_collection_api_handler.h new file mode 100644 index 0000000000000000000000000000000000000000..8f9bd8c4acdebc884103d6b7d2c3a8e3f05cc600 --- /dev/null +++ b/src/api-server/handler/sm_policies_collection_api_handler.h @@ -0,0 +1,62 @@ + +/* + * Licensed to the OpenAirInterface (OAI) Software Alliance under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The OpenAirInterface Software Alliance licenses this file to You under + * the OAI Public License, Version 1.1 (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.openairinterface.org/?page_id=698 + * + * 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. + *------------------------------------------------------------------------------- + * For more information about the OpenAirInterface (OAI) Software Alliance: + * contact@openairinterface.org + */ + +/*! \file sm_policies_collection_api_handler.h + \brief + \author Stefan Spettel + \company phine.tech + \date 2023 + \email: stefan.spettel@phine.tech + */ + +#pragma once + +#include "3gpp_29.500.h" +#include "api_response.h" +#include "SmPolicyContextData.h" +#include "pcf_sm_policy_control.hpp" + +namespace oai::pcf::api { + +class sm_policies_collection_api_handler { + public: + sm_policies_collection_api_handler( + const std::shared_ptr<oai::pcf::app::pcf_smpc>& pcf_smpc, + const std::string& address) { + m_address = address; + m_smpc_service = pcf_smpc; + } + + /** + * Create SM Policy + * @param sm_policy_context_data SM context data + * @return api_response with SmPolicyDecision + */ + api_response create_sm_policy( + const model::SmPolicyContextData& sm_policy_context_data); + + private: + std::string m_address; + std::shared_ptr<oai::pcf::app::pcf_smpc> m_smpc_service; +}; + +} // namespace oai::pcf::api \ No newline at end of file diff --git a/src/api-server/impl/IndividualSMPolicyDocumentApiImpl.cpp b/src/api-server/impl/IndividualSMPolicyDocumentApiImpl.cpp index 9f210733a0db3acd98478a516eb36aa1c53c6d34..347b548ac06b6d2f3568e4d32c47b5d758525ad5 100644 --- a/src/api-server/impl/IndividualSMPolicyDocumentApiImpl.cpp +++ b/src/api-server/impl/IndividualSMPolicyDocumentApiImpl.cpp @@ -12,12 +12,9 @@ */ #include "IndividualSMPolicyDocumentApiImpl.h" -#include "sm_policy/pcf_smpc_status_code.hpp" #include "3gpp_29.500.h" -namespace oai { -namespace pcf { -namespace api { +namespace oai::pcf::api { using namespace oai::pcf::model; using namespace oai::pcf::app; @@ -26,153 +23,36 @@ using namespace oai::model::common; IndividualSMPolicyDocumentApiImpl::IndividualSMPolicyDocumentApiImpl( const std::shared_ptr<Pistache::Rest::Router>& rtr, - std::shared_ptr<pcf_smpc> smpc_service, std::string address) + const std::shared_ptr<pcf_smpc>& smpc_service, const std::string&) : IndividualSMPolicyDocumentApi(rtr) { - m_address = address; - m_smpc_service = smpc_service; + m_api_handler = + std::make_shared<individual_sm_policy_document_api_handler>(smpc_service); } void IndividualSMPolicyDocumentApiImpl::delete_sm_policy( const std::string& smPolicyId, const SmPolicyDeleteData& smPolicyDeleteData, Pistache::Http::ResponseWriter& response) { - ProblemDetails problem_details; - std::string problem_description; - std::string content_type = "application/problem+json"; - nlohmann::json json_data; - http_status_code_e http_code; - status_code res = m_smpc_service->delete_sm_policy_handler( - smPolicyId, smPolicyDeleteData, problem_description); - - switch (res) { - case status_code::OK: - http_code = http_status_code_e::HTTP_STATUS_CODE_204_NO_CONTENT; - break; - - case status_code::NOT_FOUND: - problem_details.setDetail(problem_description); - // This is not defined in the standard - problem_details.setCause("SM_POLICY_ID_NOT_FOUND"); - http_code = http_status_code_e::HTTP_STATUS_CODE_404_NOT_FOUND; - break; - - default: - problem_details.setDetail("Internal Service Error: Unknown return code."); - problem_details.setCause("INTERNAL_ERROR"); - http_code = - http_status_code_e::HTTP_STATUS_CODE_500_INTERNAL_SERVER_ERROR; - } - - if (res == status_code::OK) { - response.send(Pistache::Http::Code(http_code)); - } else { - response.headers().add<Pistache::Http::Header::ContentType>( - Pistache::Http::Mime::MediaType(content_type)); - to_json(json_data, problem_details); - response.send(Pistache::Http::Code(http_code), json_data.dump().c_str()); - } + api_response resp = + m_api_handler->delete_sm_policy(smPolicyId, smPolicyDeleteData); + response.headers() = resp.headers; + response.send(Pistache::Http::Code(resp.status_code), resp.body); } void IndividualSMPolicyDocumentApiImpl::get_sm_policy( const std::string& smPolicyId, Pistache::Http::ResponseWriter& response) { - ProblemDetails problem_details; - std::string problem_description; - std::string content_type = "application/problem+json"; - nlohmann::json json_data; - http_status_code_e http_code; - - SmPolicyControl sm_policy_control; - - status_code res = m_smpc_service->get_sm_policy_handler( - smPolicyId, sm_policy_control, problem_description); - - switch (res) { - case status_code::OK: - http_code = http_status_code_e::HTTP_STATUS_CODE_200_OK; - content_type = "application/json"; - break; - - case status_code::NOT_FOUND: - problem_details.setDetail(problem_description); - // This is not defined in the standard - problem_details.setCause("SM_POLICY_ID_NOT_FOUND"); - http_code = http_status_code_e::HTTP_STATUS_CODE_404_NOT_FOUND; - break; - - default: - problem_details.setDetail("Internal Service Error: Unknown return code."); - problem_details.setCause("INTERNAL_ERROR"); - http_code = - http_status_code_e::HTTP_STATUS_CODE_500_INTERNAL_SERVER_ERROR; - } - - if (res == status_code::OK) { - to_json(json_data, sm_policy_control); - } else { - to_json(json_data, problem_details); - } - - response.headers().add<Pistache::Http::Header::ContentType>( - Pistache::Http::Mime::MediaType(content_type)); - - response.send(Pistache::Http::Code(http_code), json_data.dump().c_str()); + api_response resp = m_api_handler->get_sm_policy(smPolicyId); + response.headers() = resp.headers; + response.send(Pistache::Http::Code(resp.status_code), resp.body); } void IndividualSMPolicyDocumentApiImpl::update_sm_policy( const std::string& smPolicyId, const SmPolicyUpdateContextData& smPolicyUpdateContextData, Pistache::Http::ResponseWriter& response) { - ProblemDetails problem_details; - std::string problem_description = ""; - std::string content_type = "application/problem+json"; - nlohmann::json json_data; - http_status_code_e http_code; - - SmPolicyDecision decision_update; - - status_code res = m_smpc_service->update_sm_policy_handler( - smPolicyId, smPolicyUpdateContextData, decision_update, - problem_description); - - problem_details.setDetail(problem_description); - - switch (res) { - case status_code::OK: - content_type = "application/json"; - http_code = http_status_code_e::HTTP_STATUS_CODE_200_OK; - break; - case status_code::INVALID_PARAMETERS: - http_code = http_status_code_e::HTTP_STATUS_CODE_400_BAD_REQUEST; - problem_details.setCause("ERROR_INITIAL_PARAMETERS"); - break; - case status_code::CONTEXT_DENIED: - // should map to 403 but not defined in standard for this request - http_code = http_status_code_e::HTTP_STATUS_CODE_400_BAD_REQUEST; - problem_details.setCause("ERROR_INITIAL_PARAMETERS"); - break; - case status_code::NOT_FOUND: - // TODO This is not defined in the standard, but this scenario is missig - // we could map it to the 400 Bad request but that is somehow misleading - problem_details.setCause("SM_POLICY_ID_NOT_FOUND"); - http_code = http_status_code_e::HTTP_STATUS_CODE_404_NOT_FOUND; - break; - default: - problem_details.setCause("INTERNAL_ERROR"); - http_code = - http_status_code_e::HTTP_STATUS_CODE_500_INTERNAL_SERVER_ERROR; - } - - if (res == status_code::OK) { - to_json(json_data, decision_update); - } else { - to_json(json_data, problem_details); - } - - response.headers().add<Pistache::Http::Header::ContentType>( - Pistache::Http::Mime::MediaType(content_type)); - - response.send(Pistache::Http::Code(http_code), json_data.dump().c_str()); + api_response resp = + m_api_handler->update_sm_policy(smPolicyId, smPolicyUpdateContextData); + response.headers() = resp.headers; + response.send(Pistache::Http::Code(resp.status_code), resp.body); } -} // namespace api -} // namespace pcf -} // namespace oai +} // namespace oai::pcf::api diff --git a/src/api-server/impl/IndividualSMPolicyDocumentApiImpl.h b/src/api-server/impl/IndividualSMPolicyDocumentApiImpl.h old mode 100755 new mode 100644 index ffc1da101c987b461a82c7b5d19383f19914f795..b957acd8a04f62f7ff44e6f8f39b40add67713c4 --- a/src/api-server/impl/IndividualSMPolicyDocumentApiImpl.h +++ b/src/api-server/impl/IndividualSMPolicyDocumentApiImpl.h @@ -17,8 +17,7 @@ * */ -#ifndef INDIVIDUAL_SM_POLICY_DOCUMENT_API_IMPL_H_ -#define INDIVIDUAL_SM_POLICY_DOCUMENT_API_IMPL_H_ +#pragma once #include <pistache/endpoint.h> #include <pistache/http.h> @@ -36,10 +35,9 @@ #include <string> #include "pcf_app.hpp" +#include "individual_sm_policy_document_api_handler.h" -namespace oai { -namespace pcf { -namespace api { +namespace oai::pcf::api { using namespace oai::pcf::model; using namespace pcf; @@ -49,28 +47,25 @@ class IndividualSMPolicyDocumentApiImpl public: explicit IndividualSMPolicyDocumentApiImpl( const std::shared_ptr<Pistache::Rest::Router>& rtr, - const std::shared_ptr<pcf::app::pcf_smpc> smpc_service, - std::string m_address); + const std::shared_ptr<pcf::app::pcf_smpc>& smpc_service, + const std::string& m_address); ~IndividualSMPolicyDocumentApiImpl() override = default; void delete_sm_policy( const std::string& smPolicyId, const SmPolicyDeleteData& smPolicyDeleteData, - Pistache::Http::ResponseWriter& response); + Pistache::Http::ResponseWriter& response) override; void get_sm_policy( - const std::string& smPolicyId, Pistache::Http::ResponseWriter& response); + const std::string& smPolicyId, + Pistache::Http::ResponseWriter& response) override; void update_sm_policy( const std::string& smPolicyId, const SmPolicyUpdateContextData& smPolicyUpdateContextData, - Pistache::Http::ResponseWriter& response); + Pistache::Http::ResponseWriter& response) override; private: std::string m_address; - std::shared_ptr<app::pcf_smpc> m_smpc_service; + std::shared_ptr<individual_sm_policy_document_api_handler> m_api_handler; }; -} // namespace api -} // namespace pcf -} // namespace oai - -#endif +} // namespace oai::pcf::api diff --git a/src/api-server/impl/SMPoliciesCollectionApiImpl.cpp b/src/api-server/impl/SMPoliciesCollectionApiImpl.cpp index a57058c9fd15cd2c8c41a04d009803db2d29eeeb..bc99da85d61222d855d0f3cf306cd77d90c4ab53 100644 --- a/src/api-server/impl/SMPoliciesCollectionApiImpl.cpp +++ b/src/api-server/impl/SMPoliciesCollectionApiImpl.cpp @@ -12,13 +12,10 @@ */ #include "SMPoliciesCollectionApiImpl.h" -#include "sm_policy/pcf_smpc_status_code.hpp" #include "3gpp_29.500.h" #include "logger.hpp" -namespace oai { -namespace pcf { -namespace api { +namespace oai::pcf::api { using namespace oai::pcf::model; using namespace oai::pcf::app; @@ -27,74 +24,19 @@ using namespace oai::model::common; SMPoliciesCollectionApiImpl::SMPoliciesCollectionApiImpl( const std::shared_ptr<Pistache::Rest::Router>& rtr, - const std::shared_ptr<pcf_smpc> smpc_service, std::string address) + const std::shared_ptr<pcf_smpc>& smpc_service, const std::string& address) : SMPoliciesCollectionApi(rtr) { - this->m_address = address; - this->smpc_service = smpc_service; + m_api_handler = std::make_shared<sm_policies_collection_api_handler>( + sm_policies_collection_api_handler(smpc_service, address)); } void SMPoliciesCollectionApiImpl::create_sm_policy( const SmPolicyContextData& smPolicyContextData, Pistache::Http::ResponseWriter& response) { - http_status_code_e http_code; - std::string cause; - ProblemDetails problem_details; - SmPolicyDecision decision; - std::string details_string = ""; - std::string association_id = ""; - std::string location = ""; - std::string content_type = "application/problem+json"; + api_response api_resp = m_api_handler->create_sm_policy(smPolicyContextData); + response.headers() = api_resp.headers; - status_code res = smpc_service->create_sm_policy_handler( - smPolicyContextData, decision, association_id, details_string); - nlohmann::json json_data; - - switch (res) { - case status_code::CREATED: - http_code = http_status_code_e::HTTP_STATUS_CODE_201_CREATED; - location = m_address + base + "/sm-policies/" + association_id; - content_type = "application/json"; - break; - - case status_code::USER_UNKOWN: - problem_details.setCause("USER_UNKOWN"); - problem_details.setDetail(details_string); - http_code = http_status_code_e::HTTP_STATUS_CODE_400_BAD_REQUEST; - break; - - case status_code::INVALID_PARAMETERS: - problem_details.setCause("ERROR_INITIAL_PARAMETERS"); - problem_details.setDetail(details_string); - http_code = http_status_code_e::HTTP_STATUS_CODE_400_BAD_REQUEST; - break; - - case status_code::CONTEXT_DENIED: - problem_details.setCause("POLICY_CONTEXT_DENIED"); - problem_details.setDetail(details_string); - http_code = http_status_code_e::HTTP_STATUS_CODE_403_FORBIDDEN; - break; - - default: - Logger::pcf_app().error("Unknown error code"); - http_code = - http_status_code_e::HTTP_STATUS_CODE_500_INTERNAL_SERVER_ERROR; - problem_details.setCause("INTERNAL_ERROR"); - problem_details.setDetail("Internal Service Error: Unknown return code."); - } - - if (http_code != http_status_code_e::HTTP_STATUS_CODE_201_CREATED) { - to_json(json_data, problem_details); - } else { - to_json(json_data, decision); - response.headers().add<Pistache::Http::Header::Location>(location); - } - - response.headers().add<Pistache::Http::Header::ContentType>( - Pistache::Http::Mime::MediaType(content_type)); - - response.send(Pistache::Http::Code(http_code), json_data.dump().c_str()); + response.send(Pistache::Http::Code(api_resp.status_code), api_resp.body); } -} // namespace api -} // namespace pcf -} // namespace oai +} // namespace oai::pcf::api diff --git a/src/api-server/impl/SMPoliciesCollectionApiImpl.h b/src/api-server/impl/SMPoliciesCollectionApiImpl.h old mode 100755 new mode 100644 index cdb357a076efc413cf302200dd824afa03d5594d..74ac948a50bb888b86529a0947f2115340e3eb07 --- a/src/api-server/impl/SMPoliciesCollectionApiImpl.h +++ b/src/api-server/impl/SMPoliciesCollectionApiImpl.h @@ -17,27 +17,25 @@ * */ -#ifndef SM_POLICIES_COLLECTION_API_IMPL_H_ -#define SM_POLICIES_COLLECTION_API_IMPL_H_ +#pragma once #include <pistache/endpoint.h> #include <pistache/http.h> #include <pistache/router.h> #include <memory> #include <optional> +#include <string> #include <SMPoliciesCollectionApi.h> #include "ProblemDetails.h" #include "SmPolicyContextData.h" #include "SmPolicyDecision.h" -#include <string> #include "pcf_sm_policy_control.hpp" +#include "sm_policies_collection_api_handler.h" -namespace oai { -namespace pcf { -namespace api { +namespace oai::pcf::api { using namespace oai::pcf::model; using namespace pcf; @@ -47,20 +45,16 @@ class SMPoliciesCollectionApiImpl public: explicit SMPoliciesCollectionApiImpl( const std::shared_ptr<Pistache::Rest::Router>& rtr, - const std::shared_ptr<app::pcf_smpc> smpc_service, std::string address); + const std::shared_ptr<app::pcf_smpc>& smpc_service, + const std::string& address); ~SMPoliciesCollectionApiImpl() override = default; void create_sm_policy( const SmPolicyContextData& smPolicyContextData, - Pistache::Http::ResponseWriter& response); + Pistache::Http::ResponseWriter& response) override; private: - std::string m_address; - std::shared_ptr<app::pcf_smpc> smpc_service; + std::shared_ptr<sm_policies_collection_api_handler> m_api_handler; }; -} // namespace api -} // namespace pcf -} // namespace oai - -#endif +} // namespace oai::pcf::api diff --git a/src/api-server/pcf-api-server.cpp b/src/api-server/pcf-api-server.cpp index 809d2af5412a04cd339d997e71cc6b2b7f61c7a6..682b13e54cd1f38ed6b04db884ec2943d72feb9e 100644 --- a/src/api-server/pcf-api-server.cpp +++ b/src/api-server/pcf-api-server.cpp @@ -69,7 +69,7 @@ void setUpUnixSignals(std::vector<int> quitSignals) { } #endif -// using namespace oai::pcf::api; +using namespace oai::pcf::api; void PCFApiServer::init(size_t thr) { auto opts = Pistache::Http::Endpoint::options().threads(thr); @@ -87,6 +87,7 @@ void PCFApiServer::start() { m_httpEndpoint->setHandler(m_router->handler()); m_httpEndpoint->serve(); } + void PCFApiServer::shutdown() { m_httpEndpoint->shutdown(); m_smPoliciesCollectionApi = nullptr; diff --git a/src/api-server/pcf-api-server.hpp b/src/api-server/pcf-api-server.hpp index 88b0a6714f43e128ecd1adffc4cef3b8d447d3d6..5bdd9fbc471ec57960283fa55085feb7cb93b889 100644 --- a/src/api-server/pcf-api-server.hpp +++ b/src/api-server/pcf-api-server.hpp @@ -31,8 +31,7 @@ * contact@openairinterface.org */ -#ifndef FILE_PCF_API_SERVER_SEEN -#define FILE_PCF_API_SERVER_SEEN +#pragma once //#include "IndividualSMPolicyDocumentApi.h" @@ -50,6 +49,8 @@ #include "SMPoliciesCollectionApiImpl.h" #include "IndividualSMPolicyDocumentApiImpl.h" +namespace oai::pcf::api { + class PCFApiServer { public: PCFApiServer( @@ -84,5 +85,4 @@ class PCFApiServer { std::shared_ptr<oai::pcf::api::IndividualSMPolicyDocumentApiImpl> m_individualSmPolicyDocumentApi; }; - -#endif +} // namespace oai::pcf::api \ No newline at end of file diff --git a/src/api-server/pcf-http2-server.cpp b/src/api-server/pcf-http2-server.cpp index 1c7039a8603a60d29a6f3861b7536938ff70b671..efa3d35644b0dd0ac7b8bb557f59f38f540e6b15 100644 --- a/src/api-server/pcf-http2-server.cpp +++ b/src/api-server/pcf-http2-server.cpp @@ -21,9 +21,9 @@ /*! \file pcf_http2-server.h \brief - \author Rohan Kharade + \author Rohan Kharade, Stefan Spettel \company Openairinterface Software Allianse - \date 2022 + \date 2023 \email: rohan.kharade@openairinterface.org */ @@ -37,13 +37,15 @@ #include "3gpp_29.500.h" #include "logger.hpp" -#include "pcf.h" #include "pcf_config.hpp" +#include "api_defs.h" +#include "SmPolicyContextData.h" using namespace nghttp2::asio_http2; using namespace nghttp2::asio_http2::server; using namespace oai::pcf::model; using namespace oai::pcf::config; +using namespace oai::pcf::api; extern std::unique_ptr<pcf_config> pcf_cfg; @@ -55,41 +57,152 @@ void pcf_http2_server::start() { std::string nfId = {}; std::string subscriptionID = {}; - // Get list of supported APIs + // SM Policies Collection API server.handle( - "/", [&](const request& request, const response& /* response */) { - request.on_data([&](const uint8_t* /* data */, std::size_t /* len */) { - if (request.method().compare("GET") == 0) { - // this->get_api_list(response); + sm_policies::get_route(), + [&](const request& request, const response& response) { + if (request.method() != "POST") { + handle_method_not_exists(response, request); + return; + } + auto request_body = std::make_shared<std::stringstream>(); + + request.on_data( + [&, request_body](const uint8_t* data, std::size_t len) { + if (len > 0) { + std::copy( + data, data + len, + std::ostream_iterator<uint8_t>(*request_body)); + return; + } + SmPolicyContextData context; + try { + nlohmann::json::parse(request_body->str()).get_to(context); + context.validate(); + api_response resp = + m_collection_api_handler->create_sm_policy(context); + auto h_map = convert_headers(resp); + response.write_head( + static_cast<unsigned int>(resp.status_code), h_map); + response.end(resp.body); + return; + } catch (std::exception& e) { + handle_parsing_error(response, e); + return; + } + }); + }); + + // Individual SM Policy + // We match for sm-policies/* + server.handle( + sm_policies::get_route() + "/", + [&](const request& request, const response& response) { + std::vector<std::string> split_result; + boost::split(split_result, request.uri().path, boost::is_any_of("/")); + bool is_update = false; + bool is_delete = false; + bool is_get = false; + std::string policy_id; + if (split_result[split_result.size() - 1] == "delete") { + is_delete = true; + policy_id = split_result[split_result.size() - 2]; + } else if (split_result[split_result.size() - 1] == "update") { + is_update = true; + policy_id = split_result[split_result.size() - 2]; + } else { + is_get = true; + policy_id = split_result[split_result.size() - 1]; + } + if ((is_delete || is_update) && request.method() != "POST") { + handle_method_not_exists(response, request); + return; + } + if (is_get && request.method() != "GET") { + handle_method_not_exists(response, request); + return; + } + auto request_body = std::make_shared<std::stringstream>(); + + request.on_data([&, request_body, is_get, is_update, is_delete, + policy_id](const uint8_t* data, std::size_t len) { + if (len > 0) { + std::copy( + data, data + len, + std::ostream_iterator<uint8_t>(*request_body)); + return; + } + SmPolicyDeleteData delete_data; + SmPolicyUpdateContextData update_context_data; + api_response resp; + try { + if (is_update) { + nlohmann::json::parse(request_body->str()) + .get_to(update_context_data); + update_context_data.validate(); + resp = m_individual_api_handler->update_sm_policy( + policy_id, update_context_data); + } else if (is_delete) { + nlohmann::json::parse(request_body->str()).get_to(delete_data); + delete_data.validate(); + resp = m_individual_api_handler->delete_sm_policy( + policy_id, delete_data); + } else if (is_get) { + resp = m_individual_api_handler->get_sm_policy(policy_id); + } + auto h_map = convert_headers(resp); + response.write_head( + static_cast<unsigned int>(resp.status_code), h_map); + response.end(resp.body); + return; + } catch (std::exception& e) { + handle_parsing_error(response, e); + return; } }); }); + // Default Route + server.handle("/", [&](const request& request, const response& response) { + handle_method_not_exists(response, request); + return; + }); + if (server.listen_and_serve(ec, m_address, std::to_string(m_port))) { - std::cerr << "HTTP Server error: " << ec.message() << std::endl; + Logger::pcf_sbi().error("HTTP Server error: %s", ec.message()); } } -//------------------------------------------------------------------------------ - -//------------------------------------------------------------------------------ -// void pcf_http2_server::get_api_list(const response &response) { -// int http_code = 0; -// nlohmann::json json_data = {}; -// std::string content_type = "application/json"; -// header_map h; -// h.emplace("content-type", header_value{content_type}); -// if (pcf_cfg.get_api_list(json_data)) { -// http_code = HTTP_STATUS_CODE_200_OK; -// response.write_head(http_code, h); -// response.end(json_data.dump(4).c_str()); -// } else { -// http_code = HTTP_STATUS_CODE_503_SERVICE_UNAVAILABLE; -// response.write_head(http_code, h); -// response.end(); -// } -// } -//------------------------------------------------------------------------------ void pcf_http2_server::stop() { server.stop(); } + +void pcf_http2_server::handle_method_not_exists( + const response& response, const request& request) { + Logger::pcf_sbi().warn( + "Invalid route/method called: %s : %s", request.method(), + request.uri().path); + response.write_head(static_cast<unsigned int>( + http_status_code_e::HTTP_STATUS_CODE_404_NOT_FOUND)); + response.end("The requested method does not exist"); +} + +void pcf_http2_server::handle_parsing_error( + const response& response, const std::exception& ex) { + Logger::pcf_sbi().warn("Parsing error: %s", ex.what()); + response.write_head(static_cast<unsigned int>( + http_status_code_e::HTTP_STATUS_CODE_400_BAD_REQUEST)); + // for security reasons it is better to not give the internal exception to the + // user, we can also decide to change that + response.end("Could not parse JSON data"); +} + +header_map pcf_http2_server::convert_headers(const api_response& response) { + header_map h_map; + for (const auto& hdr : response.headers.list()) { + std::stringstream ss; + hdr->write(ss); + h_map.emplace(hdr->name(), header_value{ss.str(), false}); + } + return h_map; +} diff --git a/src/api-server/pcf-http2-server.hpp b/src/api-server/pcf-http2-server.hpp index 7350b0bd885af00358bb5c0ed13a4e47d91d8359..274d5a8eec3d4049158cdbc7655666f16770b5a6 100644 --- a/src/api-server/pcf-http2-server.hpp +++ b/src/api-server/pcf-http2-server.hpp @@ -21,14 +21,13 @@ /*! \file pcf_http2-server.h \brief - \author Rohan Kharade + \author Rohan Kharade, Stefan Spettel \company Openairinterface Software Allianse \date 2022 \email: rohan.kharade@openairinterface.org */ -#ifndef FILE_PCF_HTTP2_SERVER_SEEN -#define FILE_PCF_HTTP2_SERVER_SEEN +#pragma once #include "conversions.hpp" #include "pcf.h" @@ -38,16 +37,28 @@ #include <nghttp2/asio_http2_server.h> #include "IndividualSMPolicyDocumentApiImpl.h" #include "SMPoliciesCollectionApiImpl.h" +#include "sm_policies_collection_api_handler.h" +#include "individual_sm_policy_document_api_handler.h" + +namespace oai::pcf::api { class pcf_http2_server { public: pcf_http2_server( const std::string& addr, uint32_t port, const std::unique_ptr<oai::pcf::app::pcf_app>& pcf_app_inst) - : m_address(addr), - m_port(port), - server(), - smpc_service(pcf_app_inst->get_pcf_smpc_service()){}; + : m_address(addr), m_port(port), server() { + // TODO hardcode http string, how to handle https + std::string address = "http://" + addr + ":" + std::to_string(port); + + m_collection_api_handler = + std::make_shared<sm_policies_collection_api_handler>( + pcf_app_inst->get_pcf_smpc_service(), address); + + m_individual_api_handler = + std::make_shared<individual_sm_policy_document_api_handler>( + pcf_app_inst->get_pcf_smpc_service()); + }; void start(); void init(size_t /* thr */) {} @@ -63,7 +74,20 @@ class pcf_http2_server { nghttp2::asio_http2::server::http2 server; - std::shared_ptr<oai::pcf::app::pcf_smpc> smpc_service; + std::shared_ptr<sm_policies_collection_api_handler> m_collection_api_handler; + std::shared_ptr<individual_sm_policy_document_api_handler> + m_individual_api_handler; + + static void handle_method_not_exists( + const nghttp2::asio_http2::server::response& response, + const nghttp2::asio_http2::server::request& request); + + static void handle_parsing_error( + const nghttp2::asio_http2::server::response& response, + const std::exception& ex); + + static nghttp2::asio_http2::header_map convert_headers( + const api_response& response); }; -#endif +} // namespace oai::pcf::api diff --git a/src/common/pcf.h b/src/common/pcf.h index 2bf2861e7ba561f13714c2f297f1f69df07695af..caa8722a5fc219c816046978309be1b2eba283eb 100644 --- a/src/common/pcf.h +++ b/src/common/pcf.h @@ -151,6 +151,4 @@ typedef struct nf_service_s { #define AMF_NUMBER_RETRIES 3 #define UDM_NUMBER_RETRIES 3 -#define SM_POLICY_API_NAME "npcf-smpolicycontrol"; - #endif diff --git a/src/oai_pcf/CMakeLists.txt b/src/oai_pcf/CMakeLists.txt index 024b3012007046683dc14c9535f3de1f426b7640..2780ca581879ddeadf3c5abf31f7d9586508e056 100644 --- a/src/oai_pcf/CMakeLists.txt +++ b/src/oai_pcf/CMakeLists.txt @@ -278,6 +278,7 @@ include_directories(${SRC_TOP_DIR}/api-server) include_directories(${SRC_TOP_DIR}/api-server/api) include_directories(${SRC_TOP_DIR}/api-server/impl) include_directories(${SRC_TOP_DIR}/api-server/model) +include_directories(${SRC_TOP_DIR}/api-server/handler) add_executable(pcf ${SRC_TOP_DIR}/oai_pcf/main.cpp diff --git a/src/oai_pcf/main.cpp b/src/oai_pcf/main.cpp index 922900d818daa9f3dd30c2471905e06f8fa780c0..46bef051e68e74f2ad61bdd89c5ac85f3b0b6d86 100644 --- a/src/oai_pcf/main.cpp +++ b/src/oai_pcf/main.cpp @@ -32,6 +32,7 @@ using namespace std; using namespace oai::pcf::app; using namespace oai::pcf::config; using namespace oai::utils; +using namespace oai::pcf::api; using namespace oai::config; diff --git a/src/pcf_app/pcf_nrf.cpp b/src/pcf_app/pcf_nrf.cpp index 8c38b49102103fd5a12bef03286da913e260cc14..6e282a355946433bacd599758ce7416cfac5a696 100644 --- a/src/pcf_app/pcf_nrf.cpp +++ b/src/pcf_app/pcf_nrf.cpp @@ -34,6 +34,7 @@ #include "pcf_config.hpp" #include "pcf_client.hpp" #include "Snssai.h" +#include "api_defs.h" #include <boost/uuid/random_generator.hpp> #include <boost/uuid/uuid_io.hpp> @@ -80,8 +81,8 @@ void pcf_nrf::generate_pcf_profile() { // NF services nf_service_t nf_service = {}; - nf_service.service_instance_id = SM_POLICY_API_NAME; - nf_service.service_name = SM_POLICY_API_NAME; + nf_service.service_instance_id = oai::pcf::api::sm_policies::API_NAME; + nf_service.service_name = oai::pcf::api::sm_policies::API_NAME; nf_service_version_t version = {}; version.api_version_in_uri = pcf_cfg->local().get_sbi().get_api_version(); version.api_full_version = "1.0.0"; // TODO: to be updated